On Thu, Jun 20, 2019 at 2:51 PM Maximilian Luz <luzmaximilian@xxxxxxxxx> wrote: > > Power and volume button support for 5th and 6th genration Microsoft > Surface devices via soc_button_array. > > Note that these devices use the same MSHW0040 device as on the Surface > Pro 4, however the implementation is different (GPIOs vs. ACPI > notifications). Thus some checking is required to ensure we only load > this driver on the correct devices. > Either I need an Ack from Dmitry, or it should go via his tree. > Signed-off-by: Maximilian Luz <luzmaximilian@xxxxxxxxx> > --- > drivers/input/misc/soc_button_array.c | 134 +++++++++++++++++++++++--- > 1 file changed, 122 insertions(+), 12 deletions(-) > > diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c > index 5e59f8e57f8e..157f53a2bd51 100644 > --- a/drivers/input/misc/soc_button_array.c > +++ b/drivers/input/misc/soc_button_array.c > @@ -25,6 +25,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,20 @@ 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 +371,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 +411,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 }, > + > { } > }; > > -- > 2.22.0 > -- With Best Regards, Andy Shevchenko