linux-surface/patches/4.19/0003-buttons.patch

284 lines
8 KiB
Diff
Raw Normal View History

2019-07-06 23:07:34 +00:00
From 65be92a4e7a1373a08dc1d75892dc6cafef830d0 Mon Sep 17 00:00:00 2001
2019-07-02 22:36:37 +00:00
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Tue, 2 Jul 2019 23:49:56 +0200
Subject: [PATCH 03/12] buttons
2019-01-27 16:01:27 +00:00
---
2019-07-06 23:07:34 +00:00
drivers/input/misc/soc_button_array.c | 151 ++++++++++++++++++++--
2019-07-02 22:36:37 +00:00
drivers/platform/x86/surfacepro3_button.c | 38 ++++++
2019-07-06 23:07:34 +00:00
2 files changed, 176 insertions(+), 13 deletions(-)
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-07-06 23:07:34 +00:00
index 55cd6e0b409c..171d8a5c8bfd 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
@@ -29,6 +29,17 @@ struct soc_button_info {
2019-01-27 16:01:27 +00:00
bool wakeup;
};
+/**
+ * struct soc_device_data - driver data for different device types
+ * @button_info: specifications of buttons, if NULL specification is assumed to
+ * be present in _DSD
+ * @check: device-specific check (NULL means all will be accepted)
+ */
2019-01-27 16:01:27 +00:00
+struct soc_device_data {
+ struct soc_button_info *button_info;
+ 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-07-06 23:07:34 +00:00
@@ -91,8 +102,12 @@ soc_button_device_create(struct platform_device *pdev,
continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
- if (!gpio_is_valid(gpio))
+ if (gpio == -EPROBE_DEFER) {
+ error = -EPROBE_DEFER;
+ goto err_free_mem;
+ } else if (!gpio_is_valid(gpio)) {
continue;
+ }
gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code;
@@ -310,6 +325,7 @@ static int soc_button_probe(struct platform_device *pdev)
2019-01-27 16:01:27 +00:00
{
struct device *dev = &pdev->dev;
const struct acpi_device_id *id;
+ struct soc_device_data *device_data;
struct soc_button_info *button_info;
struct soc_button_data *priv;
struct platform_device *pd;
2019-07-06 23:07:34 +00:00
@@ -320,18 +336,20 @@ static int soc_button_probe(struct platform_device *pdev)
2019-01-27 16:01:27 +00:00
if (!id)
return -ENODEV;
- if (!id->driver_data) {
+ device_data = (struct soc_device_data *)id->driver_data;
+ if (device_data && device_data->check) {
+ error = device_data->check(dev);
+ if (error)
2019-01-27 16:01:27 +00:00
+ return error;
+ }
+
+ if (device_data && device_data->button_info) {
2019-07-02 22:36:37 +00:00
+ button_info = (struct soc_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;
- }
-
- error = gpiod_count(dev, NULL);
- if (error < 0) {
- dev_dbg(dev, "no GPIO attached, ignoring...\n");
- return -ENODEV;
2019-01-27 16:01:27 +00:00
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
2019-07-06 23:07:34 +00:00
@@ -357,12 +375,32 @@ 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;
}
+
+static int soc_device_check_generic(struct device *dev)
+{
+ int gpios;
+
+ gpios = gpiod_count(dev, NULL);
+ if (gpios < 0) {
+ dev_dbg(dev, "no GPIO attached, ignoring...\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct soc_device_data soc_device_ACPI0011 = {
+ .button_info = NULL,
+ .check = soc_device_check_generic,
+};
+
+
/*
* Definition of buttons on the tablet. The ACPI index of each button
* is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
2019-07-06 23:07:34 +00:00
@@ -377,9 +415,96 @@ static struct soc_button_info soc_button_PNP0C40[] = {
2019-01-27 16:01:27 +00:00
{ }
};
+static struct soc_device_data soc_device_PNP0C40 = {
+ .button_info = soc_button_PNP0C40,
+ .check = soc_device_check_generic,
2019-01-27 16:01:27 +00:00
+};
+
+
2019-01-27 16:01:27 +00:00
+/*
+ * 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.
+ */
+#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);
+
+#ifdef CONFIG_ACPI
+
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;
+ u64 oem_platform_rev = 0;
+ int gpios;
2019-01-27 16:01:27 +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,
+ ACPI_TYPE_INTEGER);
2019-01-27 16:01:27 +00:00
+
+ if (result) {
+ oem_platform_rev = result->integer.value;
+ ACPI_FREE(result);
+ }
+
+ 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);
+
+ /*
+ * We are _really_ expecting GPIOs here. If we do not get any, this
+ * means the GPIO driver has not been loaded yet (which can happen).
+ * Try again later.
+ */
+ gpios = gpiod_count(dev, NULL);
+ if (gpios < 0)
2019-07-06 23:07:34 +00:00
+ return -EPROBE_DEFER;
+
+ return 0;
2019-01-27 16:01:27 +00:00
+}
+
2019-07-02 22:36:37 +00:00
+#else /* CONFIG_ACPI */
+
+static int soc_device_check_MSHW0040(struct device *dev)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_ACPI */
+
2019-01-27 16:01:27 +00:00
+/*
+ * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
+ * Obtained from DSDT/testing.
2019-01-27 16:01:27 +00:00
+ */
+static struct soc_button_info soc_button_MSHW0040[] = {
+ { "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 },
+ { }
+};
+
+static struct soc_device_data soc_device_MSHW0040 = {
+ .button_info = soc_button_MSHW0040,
+ .check = soc_device_check_MSHW0040,
+};
+
2019-01-27 16:01:27 +00:00
+
static const struct acpi_device_id soc_button_acpi_match[] = {
- { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
- { "ACPI0011", 0 },
2019-01-27 16:01:27 +00:00
+ { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
+ { "ACPI0011", (unsigned long)&soc_device_ACPI0011 },
+
+ /* Microsoft Surface Devices (5th and 6th generation) */
2019-01-27 16:01:27 +00:00
+ { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
+
2019-01-27 16:01:27 +00:00
{ }
};
diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
index 1b491690ce07..eaec30380b11 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 =
+ 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
@@ -146,6 +152,34 @@ 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.
+ */
+static int surface_button_check_MSHW0040(struct acpi_device *dev)
+{
+ acpi_handle handle = dev->handle;
+ union acpi_object *result;
+ u64 oem_platform_rev = 0;
+
+ // 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
+
+ if (result) {
+ oem_platform_rev = result->integer.value;
+ ACPI_FREE(result);
+ }
+
+ dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
+
+ return oem_platform_rev == 0 ? 0 : -ENODEV;
+}
+
+
static int surface_button_add(struct acpi_device *device)
{
struct surface_button *button;
@@ -158,6 +192,10 @@ static int surface_button_add(struct acpi_device *device)
2019-01-27 16:01:27 +00:00
strlen(SURFACE_BUTTON_OBJ_NAME)))
return -ENODEV;
+ error = surface_button_check_MSHW0040(device);
+ if (error)
+ return error;
+
button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
if (!button)
return -ENOMEM;
--
2019-07-02 22:36:37 +00:00
2.22.0
2019-01-27 16:01:27 +00:00