buttons.patch 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
  2. index 081105a9cfca..a4388b4da98f 100644
  3. --- a/drivers/platform/x86/Kconfig
  4. +++ b/drivers/platform/x86/Kconfig
  5. @@ -1158,6 +1158,11 @@ config SURFACE_3_BUTTON
  6. ---help---
  7. This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet.
  8. +config SURFACEBOOK2_BUTTON
  9. + tristate "Power/home/volume buttons driver for Microsoft Surface Book 2/ Surface Pro (2017) tablet"
  10. + ---help---
  11. + This driver handles the power and volume buttons on the Microsoft Surface Book 2/ Surface Pro (2017) tablet.
  12. +
  13. config ACPI_SURFACE
  14. tristate "Microsoft Surface Extras"
  15. depends on ACPI
  16. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
  17. index 8fd5b93bb20d..28c4cede2d91 100644
  18. --- a/drivers/platform/x86/Makefile
  19. +++ b/drivers/platform/x86/Makefile
  20. @@ -81,6 +81,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
  21. obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o
  22. obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
  23. obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
  24. +obj-$(CONFIG_SURFACEBOOK2_BUTTON) += surfacebook2_button.o
  25. obj-$(CONFIG_ACPI_SURFACE) += surface_acpi.o
  26. obj-$(CONFIG_ACPI_SURFACE) += surface_i2c.o
  27. obj-$(CONFIG_ACPI_SURFACE) += surface_platform.o
  28. diff --git a/drivers/platform/x86/surfacebook2_button.c b/drivers/platform/x86/surfacebook2_button.c
  29. new file mode 100644
  30. index 000000000000..9a23bfd32c97
  31. --- /dev/null
  32. +++ b/drivers/platform/x86/surfacebook2_button.c
  33. @@ -0,0 +1,242 @@
  34. +/*
  35. + * Supports for Surface Book 2 and Surface Pro (2017) power and volume
  36. + * buttons.
  37. + *
  38. + * Based on soc_button_array.c:
  39. + *
  40. + * (C) Copyright 2014 Intel Corporation
  41. + *
  42. + * This program is free software; you can redistribute it and/or
  43. + * modify it under the terms of the GNU General Public License
  44. + * as published by the Free Software Foundation; version 2
  45. + * of the License.
  46. + */
  47. +
  48. +#include <linux/module.h>
  49. +#include <linux/input.h>
  50. +#include <linux/init.h>
  51. +#include <linux/kernel.h>
  52. +#include <linux/acpi.h>
  53. +#include <linux/gpio/consumer.h>
  54. +#include <linux/gpio_keys.h>
  55. +#include <linux/gpio.h>
  56. +#include <linux/platform_device.h>
  57. +
  58. +struct soc_button_info {
  59. + const char *name;
  60. + int acpi_index;
  61. + unsigned int event_type;
  62. + unsigned int event_code;
  63. + bool autorepeat;
  64. + bool wakeup;
  65. +};
  66. +
  67. +/*
  68. + * Some of the buttons like volume up/down are auto repeat, while others
  69. + * are not. To support both, we register two platform devices, and put
  70. + * buttons into them based on whether the key should be auto repeat.
  71. + */
  72. +#define BUTTON_TYPES 2
  73. +#define SURFACE_METHOD_DSM "_DSM"
  74. +
  75. +struct soc_button_data {
  76. + struct platform_device *children[BUTTON_TYPES];
  77. +};
  78. +
  79. +/*
  80. + * Get the Nth GPIO number from the ACPI object.
  81. + */
  82. +static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
  83. +{
  84. + struct gpio_desc *desc;
  85. + int gpio;
  86. +
  87. + desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
  88. + if (IS_ERR(desc))
  89. + return PTR_ERR(desc);
  90. +
  91. + gpio = desc_to_gpio(desc);
  92. +
  93. + gpiod_put(desc);
  94. +
  95. + return gpio;
  96. +}
  97. +
  98. +static struct platform_device *
  99. +soc_button_device_create(struct platform_device *pdev,
  100. + const struct soc_button_info *button_info,
  101. + bool autorepeat)
  102. +{
  103. + const struct soc_button_info *info;
  104. + struct platform_device *pd;
  105. + struct gpio_keys_button *gpio_keys;
  106. + struct gpio_keys_platform_data *gpio_keys_pdata;
  107. + int n_buttons = 0;
  108. + int gpio;
  109. + int error;
  110. +
  111. + for (info = button_info; info->name; info++)
  112. + if (info->autorepeat == autorepeat)
  113. + n_buttons++;
  114. +
  115. + gpio_keys_pdata = devm_kzalloc(&pdev->dev,
  116. + sizeof(*gpio_keys_pdata) +
  117. + sizeof(*gpio_keys) * n_buttons,
  118. + GFP_KERNEL);
  119. + if (!gpio_keys_pdata)
  120. + return ERR_PTR(-ENOMEM);
  121. +
  122. + gpio_keys = (void *)(gpio_keys_pdata + 1);
  123. + n_buttons = 0;
  124. +
  125. + for (info = button_info; info->name; info++) {
  126. + if (info->autorepeat != autorepeat)
  127. + continue;
  128. +
  129. + gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
  130. + if (!gpio_is_valid(gpio))
  131. + continue;
  132. +
  133. + gpio_keys[n_buttons].type = info->event_type;
  134. + gpio_keys[n_buttons].code = info->event_code;
  135. + gpio_keys[n_buttons].gpio = gpio;
  136. + gpio_keys[n_buttons].active_low = 1;
  137. + gpio_keys[n_buttons].desc = info->name;
  138. + gpio_keys[n_buttons].wakeup = info->wakeup;
  139. + /* These devices often use cheap buttons, use 50 ms debounce */
  140. + gpio_keys[n_buttons].debounce_interval = 50;
  141. + n_buttons++;
  142. + }
  143. +
  144. + if (n_buttons == 0) {
  145. + error = -ENODEV;
  146. + goto err_free_mem;
  147. + }
  148. +
  149. + gpio_keys_pdata->buttons = gpio_keys;
  150. + gpio_keys_pdata->nbuttons = n_buttons;
  151. + gpio_keys_pdata->rep = autorepeat;
  152. +
  153. + pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
  154. + if (!pd) {
  155. + error = -ENOMEM;
  156. + goto err_free_mem;
  157. + }
  158. +
  159. + error = platform_device_add_data(pd, gpio_keys_pdata,
  160. + sizeof(*gpio_keys_pdata));
  161. + if (error)
  162. + goto err_free_pdev;
  163. +
  164. + error = platform_device_add(pd);
  165. + if (error)
  166. + goto err_free_pdev;
  167. +
  168. + return pd;
  169. +
  170. +err_free_pdev:
  171. + platform_device_put(pd);
  172. +err_free_mem:
  173. + devm_kfree(&pdev->dev, gpio_keys_pdata);
  174. + return ERR_PTR(error);
  175. +}
  176. +
  177. +static int soc_button_remove(struct platform_device *pdev)
  178. +{
  179. + struct soc_button_data *priv = platform_get_drvdata(pdev);
  180. +
  181. + int i;
  182. +
  183. + for (i = 0; i < BUTTON_TYPES; i++)
  184. + if (priv->children[i])
  185. + platform_device_unregister(priv->children[i]);
  186. +
  187. + return 0;
  188. +}
  189. +
  190. +static int soc_button_probe(struct platform_device *pdev)
  191. +{
  192. + struct device *dev = &pdev->dev;
  193. + const struct acpi_device_id *id;
  194. + struct soc_button_info *button_info;
  195. + struct soc_button_data *priv;
  196. + struct platform_device *pd;
  197. + int i;
  198. + int error;
  199. +
  200. + id = acpi_match_device(dev->driver->acpi_match_table, dev);
  201. + if (!id)
  202. + return -ENODEV;
  203. +
  204. + if (!acpi_has_method(ACPI_HANDLE(dev), SURFACE_METHOD_DSM))
  205. + return -ENODEV;
  206. +
  207. + button_info = (struct soc_button_info *)id->driver_data;
  208. +
  209. + error = gpiod_count(dev, NULL);
  210. + if (error < 0) {
  211. + dev_dbg(dev, "no GPIO attached, ignoring...\n");
  212. + return -ENODEV;
  213. + }
  214. +
  215. + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  216. + if (!priv)
  217. + return -ENOMEM;
  218. +
  219. + platform_set_drvdata(pdev, priv);
  220. +
  221. + for (i = 0; i < BUTTON_TYPES; i++) {
  222. + pd = soc_button_device_create(pdev, button_info, i == 0);
  223. + if (IS_ERR(pd)) {
  224. + error = PTR_ERR(pd);
  225. + if (error != -ENODEV) {
  226. + soc_button_remove(pdev);
  227. + return error;
  228. + }
  229. + continue;
  230. + }
  231. +
  232. + priv->children[i] = pd;
  233. + }
  234. +
  235. + if (!priv->children[0] && !priv->children[1])
  236. + return -ENODEV;
  237. +
  238. + if (!id->driver_data)
  239. + devm_kfree(dev, button_info);
  240. +
  241. + return 0;
  242. +}
  243. +
  244. +/*
  245. + * Definition of buttons on the tablet. The ACPI index of each button
  246. + * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  247. + * Platforms"
  248. + */
  249. +static struct soc_button_info soc_button_MSHW0040[] = {
  250. + { "power", 0, EV_KEY, KEY_POWER, false, true },
  251. + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  252. + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
  253. + { }
  254. +};
  255. +
  256. +static const struct acpi_device_id soc_button_acpi_match[] = {
  257. + { "MSHW0040", (unsigned long)soc_button_MSHW0040 },
  258. + { }
  259. +};
  260. +
  261. +MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
  262. +
  263. +static struct platform_driver soc_button_driver_sb2 = {
  264. + .probe = soc_button_probe,
  265. + .remove = soc_button_remove,
  266. + .driver = {
  267. + .name = "surfacebook2_button",
  268. + .acpi_match_table = ACPI_PTR(soc_button_acpi_match),
  269. + },
  270. +};
  271. +module_platform_driver(soc_button_driver_sb2);
  272. +
  273. +MODULE_AUTHOR("Maximilian Luz");
  274. +MODULE_DESCRIPTION("Surface Book 2/Surface Pro (2017) Button Driver");
  275. +MODULE_LICENSE("GPL v2");
  276. diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
  277. index 1b491690ce07..9385262b65be 100644
  278. --- a/drivers/platform/x86/surfacepro3_button.c
  279. +++ b/drivers/platform/x86/surfacepro3_button.c
  280. @@ -22,6 +22,7 @@
  281. #define SURFACE_PRO3_BUTTON_HID "MSHW0028"
  282. #define SURFACE_PRO4_BUTTON_HID "MSHW0040"
  283. #define SURFACE_BUTTON_OBJ_NAME "VGBI"
  284. +#define SURFACE_METHOD_DSM "_DSM"
  285. #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
  286. #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
  287. @@ -158,6 +159,9 @@ static int surface_button_add(struct acpi_device *device)
  288. strlen(SURFACE_BUTTON_OBJ_NAME)))
  289. return -ENODEV;
  290. + if (acpi_has_method(device->handle, SURFACE_METHOD_DSM))
  291. + return -ENODEV;
  292. +
  293. button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
  294. if (!button)
  295. return -ENOMEM;