123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- From 3e59ef509f37b135fb12556180463af0b16c9f2f Mon Sep 17 00:00:00 2001
- From: qzed <qzed@users.noreply.github.com>
- Date: Wed, 24 Apr 2019 20:29:20 +0200
- Subject: [PATCH 03/11] buttons
- ---
- drivers/input/misc/soc_button_array.c | 133 ++++++++++++++++++++--
- drivers/platform/x86/surfacepro3_button.c | 38 +++++++
- 2 files changed, 159 insertions(+), 12 deletions(-)
- diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
- index 55cd6e0b409c..ad4d591cf179 100644
- --- a/drivers/input/misc/soc_button_array.c
- +++ b/drivers/input/misc/soc_button_array.c
- @@ -29,6 +29,17 @@ struct soc_button_info {
- 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)
- + */
- +struct soc_device_data {
- + struct soc_button_info *button_info;
- + int (*check)(struct device *dev);
- +};
- +
- /*
- * 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
- @@ -310,6 +321,7 @@ static int soc_button_probe(struct platform_device *pdev)
- {
- 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;
- @@ -320,18 +332,19 @@ static int soc_button_probe(struct platform_device *pdev)
- 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)
- + return error;
- + }
- +
- + if (device_data && device_data->button_info) {
- + button_info = (struct soc_button_info *)device_data->button_info;
- + } 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;
- }
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- @@ -357,12 +370,32 @@ static int soc_button_probe(struct platform_device *pdev)
- 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
- @@ -377,9 +410,85 @@ static struct soc_button_info soc_button_PNP0C40[] = {
- { }
- };
-
- +static struct soc_device_data soc_device_PNP0C40 = {
- + .button_info = soc_button_PNP0C40,
- + .check = soc_device_check_generic,
- +};
- +
- +
- +/*
- + * 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,
- + 0x49, 0x80, 0x35);
- +
- +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;
- +
- + // get OEM platform revision
- + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
- + MSHW0040_DSM_REVISION,
- + MSHW0040_DSM_GET_OMPR, NULL,
- + ACPI_TYPE_INTEGER);
- +
- + if (result) {
- + oem_platform_rev = result->integer.value;
- + ACPI_FREE(result);
- + }
- +
- + if (oem_platform_rev == 0)
- + return -ENODEV;
- +
- + 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)
- + return -EAGAIN;
- +
- + return 0;
- +}
- +
- +/*
- + * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
- + * Obtained from DSDT/testing.
- + */
- +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,
- +};
- +
- +
- static const struct acpi_device_id soc_button_acpi_match[] = {
- - { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
- - { "ACPI0011", 0 },
- + { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
- + { "ACPI0011", (unsigned long)&soc_device_ACPI0011 },
- +
- + /* Microsoft Surface Devices (5th and 6th generation) */
- + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
- +
- { }
- };
-
- diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
- index 1b491690ce07..eaec30380b11 100644
- --- 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);
- +
- #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)
- }
- #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);
- +
- + 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)
- 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;
- --
- 2.21.0
|