1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
261cd4822SLejun Zhu /*
361cd4822SLejun Zhu  * Supports for the button array on SoC tablets originally running
461cd4822SLejun Zhu  * Windows 8.
561cd4822SLejun Zhu  *
661cd4822SLejun Zhu  * (C) Copyright 2014 Intel Corporation
761cd4822SLejun Zhu  */
861cd4822SLejun Zhu 
961cd4822SLejun Zhu #include <linux/module.h>
1061cd4822SLejun Zhu #include <linux/input.h>
1161cd4822SLejun Zhu #include <linux/init.h>
12fa248db0SDmitry Torokhov #include <linux/irq.h>
1361cd4822SLejun Zhu #include <linux/kernel.h>
1461cd4822SLejun Zhu #include <linux/acpi.h>
1578a5b53eSHans de Goede #include <linux/dmi.h>
1661cd4822SLejun Zhu #include <linux/gpio/consumer.h>
1761cd4822SLejun Zhu #include <linux/gpio_keys.h>
18be8e7a7eSBenjamin Tissoires #include <linux/gpio.h>
1961cd4822SLejun Zhu #include <linux/platform_device.h>
2061cd4822SLejun Zhu 
218e9ada1dSHans de Goede static bool use_low_level_irq;
228e9ada1dSHans de Goede module_param(use_low_level_irq, bool, 0444);
238e9ada1dSHans de Goede MODULE_PARM_DESC(use_low_level_irq, "Use low-level triggered IRQ instead of edge triggered");
248e9ada1dSHans de Goede 
2561cd4822SLejun Zhu struct soc_button_info {
2661cd4822SLejun Zhu 	const char *name;
2761cd4822SLejun Zhu 	int acpi_index;
2861cd4822SLejun Zhu 	unsigned int event_type;
2961cd4822SLejun Zhu 	unsigned int event_code;
3061cd4822SLejun Zhu 	bool autorepeat;
3161cd4822SLejun Zhu 	bool wakeup;
32838fc808SHans de Goede 	bool active_low;
3361cd4822SLejun Zhu };
3461cd4822SLejun Zhu 
35c3941593SMaximilian Luz struct soc_device_data {
36c3941593SMaximilian Luz 	const struct soc_button_info *button_info;
37c3941593SMaximilian Luz 	int (*check)(struct device *dev);
38c3941593SMaximilian Luz };
39c3941593SMaximilian Luz 
4061cd4822SLejun Zhu /*
4161cd4822SLejun Zhu  * Some of the buttons like volume up/down are auto repeat, while others
4261cd4822SLejun Zhu  * are not. To support both, we register two platform devices, and put
4361cd4822SLejun Zhu  * buttons into them based on whether the key should be auto repeat.
4461cd4822SLejun Zhu  */
4561cd4822SLejun Zhu #define BUTTON_TYPES	2
4661cd4822SLejun Zhu 
4761cd4822SLejun Zhu struct soc_button_data {
4861cd4822SLejun Zhu 	struct platform_device *children[BUTTON_TYPES];
4961cd4822SLejun Zhu };
5061cd4822SLejun Zhu 
5161cd4822SLejun Zhu /*
5278a5b53eSHans de Goede  * Some 2-in-1s which use the soc_button_array driver have this ugly issue in
5378a5b53eSHans de Goede  * their DSDT where the _LID method modifies the irq-type settings of the GPIOs
5478a5b53eSHans de Goede  * used for the power and home buttons. The intend of this AML code is to
5578a5b53eSHans de Goede  * disable these buttons when the lid is closed.
5678a5b53eSHans de Goede  * The AML does this by directly poking the GPIO controllers registers. This is
5778a5b53eSHans de Goede  * problematic because when re-enabling the irq, which happens whenever _LID
5878a5b53eSHans de Goede  * gets called with the lid open (e.g. on boot and on resume), it sets the
5978a5b53eSHans de Goede  * irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the
6078a5b53eSHans de Goede  * type to, and expects it to be, IRQ_TYPE_EDGE_BOTH.
6178a5b53eSHans de Goede  * To work around this we don't set gpio_keys_button.gpio on these 2-in-1s,
6278a5b53eSHans de Goede  * instead we get the irq for the GPIO ourselves, configure it as
6378a5b53eSHans de Goede  * IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass
6478a5b53eSHans de Goede  * the irq in gpio_keys_button.irq. Below is a list of affected devices.
6578a5b53eSHans de Goede  */
6678a5b53eSHans de Goede static const struct dmi_system_id dmi_use_low_level_irq[] = {
6778a5b53eSHans de Goede 	{
6878a5b53eSHans de Goede 		/*
6978a5b53eSHans de Goede 		 * Acer Switch 10 SW5-012. _LID method messes with home- and
7078a5b53eSHans de Goede 		 * power-button GPIO IRQ settings. When (re-)enabling the irq
7178a5b53eSHans de Goede 		 * it ors in its own flags without clearing the previous set
7278a5b53eSHans de Goede 		 * ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW |
7378a5b53eSHans de Goede 		 * IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm.
7478a5b53eSHans de Goede 		 */
7578a5b53eSHans de Goede 		.matches = {
7678a5b53eSHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
7778a5b53eSHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
7878a5b53eSHans de Goede 		},
7978a5b53eSHans de Goede 	},
8078a5b53eSHans de Goede 	{
81e13757f5SHans de Goede 		/* Acer Switch V 10 SW5-017, same issue as Acer Switch 10 SW5-012. */
82e13757f5SHans de Goede 		.matches = {
83e13757f5SHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
84e13757f5SHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
85e13757f5SHans de Goede 		},
86e13757f5SHans de Goede 	},
87e13757f5SHans de Goede 	{
8878a5b53eSHans de Goede 		/*
8978a5b53eSHans de Goede 		 * Acer One S1003. _LID method messes with power-button GPIO
9078a5b53eSHans de Goede 		 * IRQ settings, leading to a non working power-button.
9178a5b53eSHans de Goede 		 */
9278a5b53eSHans de Goede 		.matches = {
9378a5b53eSHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
9478a5b53eSHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"),
9578a5b53eSHans de Goede 		},
9678a5b53eSHans de Goede 	},
97223f61b8SHans de Goede 	{
98223f61b8SHans de Goede 		/*
996ab2e518SMarius Hoch 		 * Lenovo Yoga Tab2 1051F/1051L, something messes with the home-button
100223f61b8SHans de Goede 		 * IRQ settings, leading to a non working home-button.
101223f61b8SHans de Goede 		 */
102223f61b8SHans de Goede 		.matches = {
103223f61b8SHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
104223f61b8SHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "60073"),
1056ab2e518SMarius Hoch 			DMI_MATCH(DMI_PRODUCT_VERSION, "1051"),
106223f61b8SHans de Goede 		},
107223f61b8SHans de Goede 	},
10878a5b53eSHans de Goede 	{} /* Terminating entry */
10978a5b53eSHans de Goede };
11078a5b53eSHans de Goede 
11178a5b53eSHans de Goede /*
11220a99a29SHans de Goede  * Some devices have a wrong entry which points to a GPIO which is
11320a99a29SHans de Goede  * required in another driver, so this driver must not claim it.
11420a99a29SHans de Goede  */
11520a99a29SHans de Goede static const struct dmi_system_id dmi_invalid_acpi_index[] = {
11620a99a29SHans de Goede 	{
11720a99a29SHans de Goede 		/*
11820a99a29SHans de Goede 		 * Lenovo Yoga Book X90F / X90L, the PNP0C40 home button entry
11920a99a29SHans de Goede 		 * points to a GPIO which is not a home button and which is
12020a99a29SHans de Goede 		 * required by the lenovo-yogabook driver.
12120a99a29SHans de Goede 		 */
12220a99a29SHans de Goede 		.matches = {
12320a99a29SHans de Goede 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
12420a99a29SHans de Goede 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
12520a99a29SHans de Goede 			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
12620a99a29SHans de Goede 		},
12720a99a29SHans de Goede 		.driver_data = (void *)1l,
12820a99a29SHans de Goede 	},
12920a99a29SHans de Goede 	{} /* Terminating entry */
13020a99a29SHans de Goede };
13120a99a29SHans de Goede 
13220a99a29SHans de Goede /*
13361cd4822SLejun Zhu  * Get the Nth GPIO number from the ACPI object.
13461cd4822SLejun Zhu  */
soc_button_lookup_gpio(struct device * dev,int acpi_index,int * gpio_ret,int * irq_ret)13578a5b53eSHans de Goede static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
13678a5b53eSHans de Goede 				  int *gpio_ret, int *irq_ret)
13761cd4822SLejun Zhu {
13861cd4822SLejun Zhu 	struct gpio_desc *desc;
13961cd4822SLejun Zhu 
140a01cd170SHans de Goede 	desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
14161cd4822SLejun Zhu 	if (IS_ERR(desc))
14261cd4822SLejun Zhu 		return PTR_ERR(desc);
14361cd4822SLejun Zhu 
14478a5b53eSHans de Goede 	*gpio_ret = desc_to_gpio(desc);
14578a5b53eSHans de Goede 	*irq_ret = gpiod_to_irq(desc);
14661cd4822SLejun Zhu 
14761cd4822SLejun Zhu 	gpiod_put(desc);
14861cd4822SLejun Zhu 
14978a5b53eSHans de Goede 	return 0;
15061cd4822SLejun Zhu }
15161cd4822SLejun Zhu 
15261cd4822SLejun Zhu static struct platform_device *
soc_button_device_create(struct platform_device * pdev,const struct soc_button_info * button_info,bool autorepeat)153042e1c79SJin Yao soc_button_device_create(struct platform_device *pdev,
15461cd4822SLejun Zhu 			 const struct soc_button_info *button_info,
15561cd4822SLejun Zhu 			 bool autorepeat)
15661cd4822SLejun Zhu {
15761cd4822SLejun Zhu 	const struct soc_button_info *info;
15861cd4822SLejun Zhu 	struct platform_device *pd;
15961cd4822SLejun Zhu 	struct gpio_keys_button *gpio_keys;
16061cd4822SLejun Zhu 	struct gpio_keys_platform_data *gpio_keys_pdata;
16120a99a29SHans de Goede 	const struct dmi_system_id *dmi_id;
16220a99a29SHans de Goede 	int invalid_acpi_index = -1;
16378a5b53eSHans de Goede 	int error, gpio, irq;
16461cd4822SLejun Zhu 	int n_buttons = 0;
16561cd4822SLejun Zhu 
1667283b47dSHans de Goede 	for (info = button_info; info->name; info++)
1677283b47dSHans de Goede 		if (info->autorepeat == autorepeat)
1687283b47dSHans de Goede 			n_buttons++;
1697283b47dSHans de Goede 
17061cd4822SLejun Zhu 	gpio_keys_pdata = devm_kzalloc(&pdev->dev,
17161cd4822SLejun Zhu 				       sizeof(*gpio_keys_pdata) +
1727283b47dSHans de Goede 					sizeof(*gpio_keys) * n_buttons,
17361cd4822SLejun Zhu 				       GFP_KERNEL);
17491cf07cdSPramod Gurav 	if (!gpio_keys_pdata)
17591cf07cdSPramod Gurav 		return ERR_PTR(-ENOMEM);
17691cf07cdSPramod Gurav 
17761cd4822SLejun Zhu 	gpio_keys = (void *)(gpio_keys_pdata + 1);
1787283b47dSHans de Goede 	n_buttons = 0;
17961cd4822SLejun Zhu 
18020a99a29SHans de Goede 	dmi_id = dmi_first_match(dmi_invalid_acpi_index);
18120a99a29SHans de Goede 	if (dmi_id)
18220a99a29SHans de Goede 		invalid_acpi_index = (long)dmi_id->driver_data;
18320a99a29SHans de Goede 
18461cd4822SLejun Zhu 	for (info = button_info; info->name; info++) {
18561cd4822SLejun Zhu 		if (info->autorepeat != autorepeat)
18661cd4822SLejun Zhu 			continue;
18761cd4822SLejun Zhu 
18820a99a29SHans de Goede 		if (info->acpi_index == invalid_acpi_index)
18920a99a29SHans de Goede 			continue;
19020a99a29SHans de Goede 
19178a5b53eSHans de Goede 		error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
19278a5b53eSHans de Goede 		if (error || irq < 0) {
193bcf05957SHans de Goede 			/*
194bcf05957SHans de Goede 			 * Skip GPIO if not present. Note we deliberately
195bcf05957SHans de Goede 			 * ignore -EPROBE_DEFER errors here. On some devices
196bcf05957SHans de Goede 			 * Intel is using so called virtual GPIOs which are not
197bcf05957SHans de Goede 			 * GPIOs at all but some way for AML code to check some
198bcf05957SHans de Goede 			 * random status bits without need a custom opregion.
199bcf05957SHans de Goede 			 * In some cases the resources table we parse points to
200bcf05957SHans de Goede 			 * such a virtual GPIO, since these are not real GPIOs
201bcf05957SHans de Goede 			 * we do not have a driver for these so they will never
202bcf05957SHans de Goede 			 * show up, therefore we ignore -EPROBE_DEFER.
203bcf05957SHans de Goede 			 */
20461cd4822SLejun Zhu 			continue;
205c3941593SMaximilian Luz 		}
20661cd4822SLejun Zhu 
20778a5b53eSHans de Goede 		/* See dmi_use_low_level_irq[] comment */
2088e9ada1dSHans de Goede 		if (!autorepeat && (use_low_level_irq ||
2098e9ada1dSHans de Goede 				    dmi_check_system(dmi_use_low_level_irq))) {
21078a5b53eSHans de Goede 			irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
21178a5b53eSHans de Goede 			gpio_keys[n_buttons].irq = irq;
21278a5b53eSHans de Goede 			gpio_keys[n_buttons].gpio = -ENOENT;
21378a5b53eSHans de Goede 		} else {
21478a5b53eSHans de Goede 			gpio_keys[n_buttons].gpio = gpio;
21578a5b53eSHans de Goede 		}
21678a5b53eSHans de Goede 
21761cd4822SLejun Zhu 		gpio_keys[n_buttons].type = info->event_type;
21861cd4822SLejun Zhu 		gpio_keys[n_buttons].code = info->event_code;
219838fc808SHans de Goede 		gpio_keys[n_buttons].active_low = info->active_low;
22061cd4822SLejun Zhu 		gpio_keys[n_buttons].desc = info->name;
22161cd4822SLejun Zhu 		gpio_keys[n_buttons].wakeup = info->wakeup;
2225c4fa2a6SHans de Goede 		/* These devices often use cheap buttons, use 50 ms debounce */
2235c4fa2a6SHans de Goede 		gpio_keys[n_buttons].debounce_interval = 50;
22461cd4822SLejun Zhu 		n_buttons++;
22561cd4822SLejun Zhu 	}
22661cd4822SLejun Zhu 
22761cd4822SLejun Zhu 	if (n_buttons == 0) {
22861cd4822SLejun Zhu 		error = -ENODEV;
22961cd4822SLejun Zhu 		goto err_free_mem;
23061cd4822SLejun Zhu 	}
23161cd4822SLejun Zhu 
23261cd4822SLejun Zhu 	gpio_keys_pdata->buttons = gpio_keys;
23361cd4822SLejun Zhu 	gpio_keys_pdata->nbuttons = n_buttons;
23461cd4822SLejun Zhu 	gpio_keys_pdata->rep = autorepeat;
23561cd4822SLejun Zhu 
23653119e51SEnrico Weigelt 	pd = platform_device_register_resndata(&pdev->dev, "gpio-keys",
23753119e51SEnrico Weigelt 					       PLATFORM_DEVID_AUTO, NULL, 0,
23853119e51SEnrico Weigelt 					       gpio_keys_pdata,
23953119e51SEnrico Weigelt 					       sizeof(*gpio_keys_pdata));
24053119e51SEnrico Weigelt 	error = PTR_ERR_OR_ZERO(pd);
24153119e51SEnrico Weigelt 	if (error) {
24253119e51SEnrico Weigelt 		dev_err(&pdev->dev,
24353119e51SEnrico Weigelt 			"failed registering gpio-keys: %d\n", error);
24461cd4822SLejun Zhu 		goto err_free_mem;
24561cd4822SLejun Zhu 	}
24661cd4822SLejun Zhu 
24761cd4822SLejun Zhu 	return pd;
24861cd4822SLejun Zhu 
24961cd4822SLejun Zhu err_free_mem:
25061cd4822SLejun Zhu 	devm_kfree(&pdev->dev, gpio_keys_pdata);
25161cd4822SLejun Zhu 	return ERR_PTR(error);
25261cd4822SLejun Zhu }
25361cd4822SLejun Zhu 
soc_button_get_acpi_object_int(const union acpi_object * obj)2544c3362f4SHans de Goede static int soc_button_get_acpi_object_int(const union acpi_object *obj)
2554c3362f4SHans de Goede {
2564c3362f4SHans de Goede 	if (obj->type != ACPI_TYPE_INTEGER)
2574c3362f4SHans de Goede 		return -1;
2584c3362f4SHans de Goede 
2594c3362f4SHans de Goede 	return obj->integer.value;
2604c3362f4SHans de Goede }
2614c3362f4SHans de Goede 
2624c3362f4SHans de Goede /* Parse a single ACPI0011 _DSD button descriptor */
soc_button_parse_btn_desc(struct device * dev,const union acpi_object * desc,int collection_uid,struct soc_button_info * info)2634c3362f4SHans de Goede static int soc_button_parse_btn_desc(struct device *dev,
2644c3362f4SHans de Goede 				     const union acpi_object *desc,
2654c3362f4SHans de Goede 				     int collection_uid,
2664c3362f4SHans de Goede 				     struct soc_button_info *info)
2674c3362f4SHans de Goede {
2684c3362f4SHans de Goede 	int upage, usage;
2694c3362f4SHans de Goede 
2704c3362f4SHans de Goede 	if (desc->type != ACPI_TYPE_PACKAGE ||
2714c3362f4SHans de Goede 	    desc->package.count != 5 ||
2724c3362f4SHans de Goede 	    /* First byte should be 1 (control) */
2734c3362f4SHans de Goede 	    soc_button_get_acpi_object_int(&desc->package.elements[0]) != 1 ||
2744c3362f4SHans de Goede 	    /* Third byte should be collection uid */
2754c3362f4SHans de Goede 	    soc_button_get_acpi_object_int(&desc->package.elements[2]) !=
2764c3362f4SHans de Goede 							    collection_uid) {
2774c3362f4SHans de Goede 		dev_err(dev, "Invalid ACPI Button Descriptor\n");
2784c3362f4SHans de Goede 		return -ENODEV;
2794c3362f4SHans de Goede 	}
2804c3362f4SHans de Goede 
2814c3362f4SHans de Goede 	info->event_type = EV_KEY;
282838fc808SHans de Goede 	info->active_low = true;
2834c3362f4SHans de Goede 	info->acpi_index =
2844c3362f4SHans de Goede 		soc_button_get_acpi_object_int(&desc->package.elements[1]);
2854c3362f4SHans de Goede 	upage = soc_button_get_acpi_object_int(&desc->package.elements[3]);
2864c3362f4SHans de Goede 	usage = soc_button_get_acpi_object_int(&desc->package.elements[4]);
2874c3362f4SHans de Goede 
2884c3362f4SHans de Goede 	/*
2894c3362f4SHans de Goede 	 * The UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e descriptors use HID
2904c3362f4SHans de Goede 	 * usage page and usage codes, but otherwise the device is not HID
2914c3362f4SHans de Goede 	 * compliant: it uses one irq per button instead of generating HID
2924c3362f4SHans de Goede 	 * input reports and some buttons should generate wakeups where as
2934c3362f4SHans de Goede 	 * others should not, so we cannot use the HID subsystem.
2944c3362f4SHans de Goede 	 *
2954c3362f4SHans de Goede 	 * Luckily all devices only use a few usage page + usage combinations,
2964c3362f4SHans de Goede 	 * so we can simply check for the known combinations here.
2974c3362f4SHans de Goede 	 */
2984c3362f4SHans de Goede 	if (upage == 0x01 && usage == 0x81) {
2994c3362f4SHans de Goede 		info->name = "power";
3004c3362f4SHans de Goede 		info->event_code = KEY_POWER;
3014c3362f4SHans de Goede 		info->wakeup = true;
302*cac20035SChristoffer Sandberg 	} else if (upage == 0x01 && usage == 0xc6) {
303*cac20035SChristoffer Sandberg 		info->name = "airplane mode switch";
304*cac20035SChristoffer Sandberg 		info->event_type = EV_SW;
305*cac20035SChristoffer Sandberg 		info->event_code = SW_RFKILL_ALL;
306*cac20035SChristoffer Sandberg 		info->active_low = false;
30739be9b6dSHans de Goede 	} else if (upage == 0x01 && usage == 0xca) {
30839be9b6dSHans de Goede 		info->name = "rotation lock switch";
30939be9b6dSHans de Goede 		info->event_type = EV_SW;
31039be9b6dSHans de Goede 		info->event_code = SW_ROTATE_LOCK;
3114c3362f4SHans de Goede 	} else if (upage == 0x07 && usage == 0xe3) {
3124c3362f4SHans de Goede 		info->name = "home";
313dd224085SHans de Goede 		info->event_code = KEY_LEFTMETA;
3144c3362f4SHans de Goede 		info->wakeup = true;
3154c3362f4SHans de Goede 	} else if (upage == 0x0c && usage == 0xe9) {
3164c3362f4SHans de Goede 		info->name = "volume_up";
3174c3362f4SHans de Goede 		info->event_code = KEY_VOLUMEUP;
3184c3362f4SHans de Goede 		info->autorepeat = true;
3194c3362f4SHans de Goede 	} else if (upage == 0x0c && usage == 0xea) {
3204c3362f4SHans de Goede 		info->name = "volume_down";
3214c3362f4SHans de Goede 		info->event_code = KEY_VOLUMEDOWN;
3224c3362f4SHans de Goede 		info->autorepeat = true;
3234c3362f4SHans de Goede 	} else {
3244c3362f4SHans de Goede 		dev_warn(dev, "Unknown button index %d upage %02x usage %02x, ignoring\n",
3254c3362f4SHans de Goede 			 info->acpi_index, upage, usage);
3264c3362f4SHans de Goede 		info->name = "unknown";
3274c3362f4SHans de Goede 		info->event_code = KEY_RESERVED;
3284c3362f4SHans de Goede 	}
3294c3362f4SHans de Goede 
3304c3362f4SHans de Goede 	return 0;
3314c3362f4SHans de Goede }
3324c3362f4SHans de Goede 
3334c3362f4SHans de Goede /* ACPI0011 _DSD btns descriptors UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e */
3344c3362f4SHans de Goede static const u8 btns_desc_uuid[16] = {
3354c3362f4SHans de Goede 	0x25, 0xd6, 0x6b, 0xfa, 0xe8, 0x9c, 0x0d, 0x47,
3364c3362f4SHans de Goede 	0xa2, 0xc7, 0xb3, 0xca, 0x36, 0xc4, 0x28, 0x2e
3374c3362f4SHans de Goede };
3384c3362f4SHans de Goede 
3394c3362f4SHans de Goede /* Parse ACPI0011 _DSD button descriptors */
soc_button_get_button_info(struct device * dev)3404c3362f4SHans de Goede static struct soc_button_info *soc_button_get_button_info(struct device *dev)
3414c3362f4SHans de Goede {
3424c3362f4SHans de Goede 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
3434c3362f4SHans de Goede 	const union acpi_object *desc, *el0, *uuid, *btns_desc = NULL;
3444c3362f4SHans de Goede 	struct soc_button_info *button_info;
3454c3362f4SHans de Goede 	acpi_status status;
3464c3362f4SHans de Goede 	int i, btn, collection_uid = -1;
3474c3362f4SHans de Goede 
3484c3362f4SHans de Goede 	status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL,
3494c3362f4SHans de Goede 					    &buf, ACPI_TYPE_PACKAGE);
3504c3362f4SHans de Goede 	if (ACPI_FAILURE(status)) {
3514c3362f4SHans de Goede 		dev_err(dev, "ACPI _DSD object not found\n");
3524c3362f4SHans de Goede 		return ERR_PTR(-ENODEV);
3534c3362f4SHans de Goede 	}
3544c3362f4SHans de Goede 
3554c3362f4SHans de Goede 	/* Look for the Button Descriptors UUID */
3564c3362f4SHans de Goede 	desc = buf.pointer;
3574c3362f4SHans de Goede 	for (i = 0; (i + 1) < desc->package.count; i += 2) {
3584c3362f4SHans de Goede 		uuid = &desc->package.elements[i];
3594c3362f4SHans de Goede 
3604c3362f4SHans de Goede 		if (uuid->type != ACPI_TYPE_BUFFER ||
3614c3362f4SHans de Goede 		    uuid->buffer.length != 16 ||
3624c3362f4SHans de Goede 		    desc->package.elements[i + 1].type != ACPI_TYPE_PACKAGE) {
3634c3362f4SHans de Goede 			break;
3644c3362f4SHans de Goede 		}
3654c3362f4SHans de Goede 
3664c3362f4SHans de Goede 		if (memcmp(uuid->buffer.pointer, btns_desc_uuid, 16) == 0) {
3674c3362f4SHans de Goede 			btns_desc = &desc->package.elements[i + 1];
3684c3362f4SHans de Goede 			break;
3694c3362f4SHans de Goede 		}
3704c3362f4SHans de Goede 	}
3714c3362f4SHans de Goede 
3724c3362f4SHans de Goede 	if (!btns_desc) {
3734c3362f4SHans de Goede 		dev_err(dev, "ACPI Button Descriptors not found\n");
374779f19acSHans de Goede 		button_info = ERR_PTR(-ENODEV);
375779f19acSHans de Goede 		goto out;
3764c3362f4SHans de Goede 	}
3774c3362f4SHans de Goede 
3784c3362f4SHans de Goede 	/* The first package describes the collection */
3794c3362f4SHans de Goede 	el0 = &btns_desc->package.elements[0];
3804c3362f4SHans de Goede 	if (el0->type == ACPI_TYPE_PACKAGE &&
3814c3362f4SHans de Goede 	    el0->package.count == 5 &&
3824c3362f4SHans de Goede 	    /* First byte should be 0 (collection) */
3834c3362f4SHans de Goede 	    soc_button_get_acpi_object_int(&el0->package.elements[0]) == 0 &&
3844c3362f4SHans de Goede 	    /* Third byte should be 0 (top level collection) */
3854c3362f4SHans de Goede 	    soc_button_get_acpi_object_int(&el0->package.elements[2]) == 0) {
3864c3362f4SHans de Goede 		collection_uid = soc_button_get_acpi_object_int(
3874c3362f4SHans de Goede 						&el0->package.elements[1]);
3884c3362f4SHans de Goede 	}
3894c3362f4SHans de Goede 	if (collection_uid == -1) {
3904c3362f4SHans de Goede 		dev_err(dev, "Invalid Button Collection Descriptor\n");
391779f19acSHans de Goede 		button_info = ERR_PTR(-ENODEV);
392779f19acSHans de Goede 		goto out;
3934c3362f4SHans de Goede 	}
3944c3362f4SHans de Goede 
3954c3362f4SHans de Goede 	/* There are package.count - 1 buttons + 1 terminating empty entry */
3964c3362f4SHans de Goede 	button_info = devm_kcalloc(dev, btns_desc->package.count,
3974c3362f4SHans de Goede 				   sizeof(*button_info), GFP_KERNEL);
398779f19acSHans de Goede 	if (!button_info) {
399779f19acSHans de Goede 		button_info = ERR_PTR(-ENOMEM);
400779f19acSHans de Goede 		goto out;
401779f19acSHans de Goede 	}
4024c3362f4SHans de Goede 
4034c3362f4SHans de Goede 	/* Parse the button descriptors */
4044c3362f4SHans de Goede 	for (i = 1, btn = 0; i < btns_desc->package.count; i++, btn++) {
4054c3362f4SHans de Goede 		if (soc_button_parse_btn_desc(dev,
4064c3362f4SHans de Goede 					      &btns_desc->package.elements[i],
4074c3362f4SHans de Goede 					      collection_uid,
408779f19acSHans de Goede 					      &button_info[btn])) {
409779f19acSHans de Goede 			button_info = ERR_PTR(-ENODEV);
410779f19acSHans de Goede 			goto out;
411779f19acSHans de Goede 		}
4124c3362f4SHans de Goede 	}
4134c3362f4SHans de Goede 
414779f19acSHans de Goede out:
415779f19acSHans de Goede 	kfree(buf.pointer);
4164c3362f4SHans de Goede 	return button_info;
4174c3362f4SHans de Goede }
4184c3362f4SHans de Goede 
soc_button_remove(struct platform_device * pdev)419042e1c79SJin Yao static int soc_button_remove(struct platform_device *pdev)
42061cd4822SLejun Zhu {
421042e1c79SJin Yao 	struct soc_button_data *priv = platform_get_drvdata(pdev);
422042e1c79SJin Yao 
42361cd4822SLejun Zhu 	int i;
42461cd4822SLejun Zhu 
42561cd4822SLejun Zhu 	for (i = 0; i < BUTTON_TYPES; i++)
42661cd4822SLejun Zhu 		if (priv->children[i])
42761cd4822SLejun Zhu 			platform_device_unregister(priv->children[i]);
428042e1c79SJin Yao 
429042e1c79SJin Yao 	return 0;
43061cd4822SLejun Zhu }
43161cd4822SLejun Zhu 
soc_button_probe(struct platform_device * pdev)432042e1c79SJin Yao static int soc_button_probe(struct platform_device *pdev)
43361cd4822SLejun Zhu {
434042e1c79SJin Yao 	struct device *dev = &pdev->dev;
435c3941593SMaximilian Luz 	const struct soc_device_data *device_data;
436c3941593SMaximilian Luz 	const struct soc_button_info *button_info;
43761cd4822SLejun Zhu 	struct soc_button_data *priv;
43861cd4822SLejun Zhu 	struct platform_device *pd;
43961cd4822SLejun Zhu 	int i;
44061cd4822SLejun Zhu 	int error;
44161cd4822SLejun Zhu 
442c3941593SMaximilian Luz 	device_data = acpi_device_get_match_data(dev);
443c3941593SMaximilian Luz 	if (device_data && device_data->check) {
444c3941593SMaximilian Luz 		error = device_data->check(dev);
445c3941593SMaximilian Luz 		if (error)
446c3941593SMaximilian Luz 			return error;
447c3941593SMaximilian Luz 	}
448042e1c79SJin Yao 
449c3941593SMaximilian Luz 	if (device_data && device_data->button_info) {
450c3941593SMaximilian Luz 		button_info = device_data->button_info;
451c3941593SMaximilian Luz 	} else {
4524c3362f4SHans de Goede 		button_info = soc_button_get_button_info(dev);
4534c3362f4SHans de Goede 		if (IS_ERR(button_info))
4544c3362f4SHans de Goede 			return PTR_ERR(button_info);
4554c3362f4SHans de Goede 	}
456042e1c79SJin Yao 
457c5097538SAndy Shevchenko 	error = gpiod_count(dev, NULL);
458c5097538SAndy Shevchenko 	if (error < 0) {
459aa45590aSGuenter Roeck 		dev_dbg(dev, "no GPIO attached, ignoring...\n");
460d912366aSHans de Goede 		return -ENODEV;
4613d5a9437SBenjamin Tissoires 	}
4623d5a9437SBenjamin Tissoires 
463aa45590aSGuenter Roeck 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
46461cd4822SLejun Zhu 	if (!priv)
46561cd4822SLejun Zhu 		return -ENOMEM;
46661cd4822SLejun Zhu 
467042e1c79SJin Yao 	platform_set_drvdata(pdev, priv);
46861cd4822SLejun Zhu 
46961cd4822SLejun Zhu 	for (i = 0; i < BUTTON_TYPES; i++) {
47061cd4822SLejun Zhu 		pd = soc_button_device_create(pdev, button_info, i == 0);
47161cd4822SLejun Zhu 		if (IS_ERR(pd)) {
47261cd4822SLejun Zhu 			error = PTR_ERR(pd);
47361cd4822SLejun Zhu 			if (error != -ENODEV) {
47461cd4822SLejun Zhu 				soc_button_remove(pdev);
47561cd4822SLejun Zhu 				return error;
47661cd4822SLejun Zhu 			}
4777740fc52SLejun Zhu 			continue;
47861cd4822SLejun Zhu 		}
47961cd4822SLejun Zhu 
48061cd4822SLejun Zhu 		priv->children[i] = pd;
48161cd4822SLejun Zhu 	}
48261cd4822SLejun Zhu 
48361cd4822SLejun Zhu 	if (!priv->children[0] && !priv->children[1])
48461cd4822SLejun Zhu 		return -ENODEV;
48561cd4822SLejun Zhu 
486c3941593SMaximilian Luz 	if (!device_data || !device_data->button_info)
4874c3362f4SHans de Goede 		devm_kfree(dev, button_info);
4884c3362f4SHans de Goede 
48961cd4822SLejun Zhu 	return 0;
49061cd4822SLejun Zhu }
49161cd4822SLejun Zhu 
4927283b47dSHans de Goede /*
4937283b47dSHans de Goede  * Definition of buttons on the tablet. The ACPI index of each button
4947283b47dSHans de Goede  * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
4957283b47dSHans de Goede  * Platforms"
4967283b47dSHans de Goede  */
497c3941593SMaximilian Luz static const struct soc_button_info soc_button_PNP0C40[] = {
498838fc808SHans de Goede 	{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
499838fc808SHans de Goede 	{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
500838fc808SHans de Goede 	{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
501838fc808SHans de Goede 	{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
502838fc808SHans de Goede 	{ "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
50361cd4822SLejun Zhu 	{ }
50461cd4822SLejun Zhu };
50561cd4822SLejun Zhu 
506c3941593SMaximilian Luz static const struct soc_device_data soc_device_PNP0C40 = {
507c3941593SMaximilian Luz 	.button_info = soc_button_PNP0C40,
508c3941593SMaximilian Luz };
509c3941593SMaximilian Luz 
5104e5d9c19SHans de Goede static const struct soc_button_info soc_button_INT33D3[] = {
5114e5d9c19SHans de Goede 	{ "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
5124e5d9c19SHans de Goede 	{ }
5134e5d9c19SHans de Goede };
5144e5d9c19SHans de Goede 
5154e5d9c19SHans de Goede static const struct soc_device_data soc_device_INT33D3 = {
5164e5d9c19SHans de Goede 	.button_info = soc_button_INT33D3,
5174e5d9c19SHans de Goede };
5184e5d9c19SHans de Goede 
519c3941593SMaximilian Luz /*
52060c7353cSHans de Goede  * Button info for Microsoft Surface 3 (non pro), this is indentical to
52160c7353cSHans de Goede  * the PNP0C40 info except that the home button is active-high.
52260c7353cSHans de Goede  *
52360c7353cSHans de Goede  * The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom
52460c7353cSHans de Goede  * version of the drivers/platform/x86/intel/hid.c 5 button array ACPI API
52560c7353cSHans de Goede  * instead. A check() callback is not necessary though as the Surface 3 Pro
52660c7353cSHans de Goede  * MSHW0028 ACPI device's resource table does not contain any GPIOs.
52760c7353cSHans de Goede  */
52860c7353cSHans de Goede static const struct soc_button_info soc_button_MSHW0028[] = {
52960c7353cSHans de Goede 	{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
53060c7353cSHans de Goede 	{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
53160c7353cSHans de Goede 	{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
53260c7353cSHans de Goede 	{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
53360c7353cSHans de Goede 	{ }
53460c7353cSHans de Goede };
53560c7353cSHans de Goede 
53660c7353cSHans de Goede static const struct soc_device_data soc_device_MSHW0028 = {
53760c7353cSHans de Goede 	.button_info = soc_button_MSHW0028,
53860c7353cSHans de Goede };
53960c7353cSHans de Goede 
54060c7353cSHans de Goede /*
541c3941593SMaximilian Luz  * Special device check for Surface Book 2 and Surface Pro (2017).
542c3941593SMaximilian Luz  * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
543c3941593SMaximilian Luz  * devices use MSHW0040 for power and volume buttons, however the way they
544c3941593SMaximilian Luz  * have to be addressed differs. Make sure that we only load this drivers
545c3941593SMaximilian Luz  * for the correct devices by checking the OEM Platform Revision provided by
546c3941593SMaximilian Luz  * the _DSM method.
547c3941593SMaximilian Luz  */
548c3941593SMaximilian Luz #define MSHW0040_DSM_REVISION		0x01
549c3941593SMaximilian Luz #define MSHW0040_DSM_GET_OMPR		0x02	// get OEM Platform Revision
550c3941593SMaximilian Luz static const guid_t MSHW0040_DSM_UUID =
551c3941593SMaximilian Luz 	GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
552c3941593SMaximilian Luz 		  0x49, 0x80, 0x35);
553c3941593SMaximilian Luz 
soc_device_check_MSHW0040(struct device * dev)554c3941593SMaximilian Luz static int soc_device_check_MSHW0040(struct device *dev)
555c3941593SMaximilian Luz {
556c3941593SMaximilian Luz 	acpi_handle handle = ACPI_HANDLE(dev);
557c3941593SMaximilian Luz 	union acpi_object *result;
558c3941593SMaximilian Luz 	u64 oem_platform_rev = 0;	// valid revisions are nonzero
559c3941593SMaximilian Luz 
560c3941593SMaximilian Luz 	// get OEM platform revision
561c3941593SMaximilian Luz 	result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
562c3941593SMaximilian Luz 					 MSHW0040_DSM_REVISION,
563c3941593SMaximilian Luz 					 MSHW0040_DSM_GET_OMPR, NULL,
564c3941593SMaximilian Luz 					 ACPI_TYPE_INTEGER);
565c3941593SMaximilian Luz 
566c3941593SMaximilian Luz 	if (result) {
567c3941593SMaximilian Luz 		oem_platform_rev = result->integer.value;
568c3941593SMaximilian Luz 		ACPI_FREE(result);
569c3941593SMaximilian Luz 	}
570c3941593SMaximilian Luz 
571c3941593SMaximilian Luz 	/*
572c3941593SMaximilian Luz 	 * If the revision is zero here, the _DSM evaluation has failed. This
573c3941593SMaximilian Luz 	 * indicates that we have a Pro 4 or Book 1 and this driver should not
574c3941593SMaximilian Luz 	 * be used.
575c3941593SMaximilian Luz 	 */
576c3941593SMaximilian Luz 	if (oem_platform_rev == 0)
577c3941593SMaximilian Luz 		return -ENODEV;
578c3941593SMaximilian Luz 
579c3941593SMaximilian Luz 	dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
580c3941593SMaximilian Luz 
581c3941593SMaximilian Luz 	return 0;
582c3941593SMaximilian Luz }
583c3941593SMaximilian Luz 
584c3941593SMaximilian Luz /*
585c3941593SMaximilian Luz  * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
586c3941593SMaximilian Luz  * Obtained from DSDT/testing.
587c3941593SMaximilian Luz  */
588c3941593SMaximilian Luz static const struct soc_button_info soc_button_MSHW0040[] = {
589838fc808SHans de Goede 	{ "power", 0, EV_KEY, KEY_POWER, false, true, true },
590838fc808SHans de Goede 	{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
591838fc808SHans de Goede 	{ "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
592c3941593SMaximilian Luz 	{ }
593c3941593SMaximilian Luz };
594c3941593SMaximilian Luz 
595c3941593SMaximilian Luz static const struct soc_device_data soc_device_MSHW0040 = {
596c3941593SMaximilian Luz 	.button_info = soc_button_MSHW0040,
597c3941593SMaximilian Luz 	.check = soc_device_check_MSHW0040,
598c3941593SMaximilian Luz };
599c3941593SMaximilian Luz 
600042e1c79SJin Yao static const struct acpi_device_id soc_button_acpi_match[] = {
601c3941593SMaximilian Luz 	{ "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
6024e5d9c19SHans de Goede 	{ "INT33D3", (unsigned long)&soc_device_INT33D3 },
6034e5d9c19SHans de Goede 	{ "ID9001", (unsigned long)&soc_device_INT33D3 },
6044c3362f4SHans de Goede 	{ "ACPI0011", 0 },
605c3941593SMaximilian Luz 
60660c7353cSHans de Goede 	/* Microsoft Surface Devices (3th, 5th and 6th generation) */
60760c7353cSHans de Goede 	{ "MSHW0028", (unsigned long)&soc_device_MSHW0028 },
608c3941593SMaximilian Luz 	{ "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
609c3941593SMaximilian Luz 
610042e1c79SJin Yao 	{ }
61161cd4822SLejun Zhu };
61261cd4822SLejun Zhu 
613042e1c79SJin Yao MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
614042e1c79SJin Yao 
615042e1c79SJin Yao static struct platform_driver soc_button_driver = {
616042e1c79SJin Yao 	.probe          = soc_button_probe,
61761cd4822SLejun Zhu 	.remove		= soc_button_remove,
618042e1c79SJin Yao 	.driver		= {
619042e1c79SJin Yao 		.name = KBUILD_MODNAME,
620042e1c79SJin Yao 		.acpi_match_table = ACPI_PTR(soc_button_acpi_match),
621042e1c79SJin Yao 	},
62261cd4822SLejun Zhu };
623042e1c79SJin Yao module_platform_driver(soc_button_driver);
62461cd4822SLejun Zhu 
62561cd4822SLejun Zhu MODULE_LICENSE("GPL");
626