0003-buttons.patch 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. From 72bd00dbd59591de9cbcb05ecabf2eaefaec6787 Mon Sep 17 00:00:00 2001
  2. From: Maximilian Luz <luzmaximilian@gmail.com>
  3. Date: Wed, 3 Jul 2019 00:25:27 +0200
  4. Subject: [PATCH 03/12] buttons
  5. ---
  6. drivers/input/misc/soc_button_array.c | 151 ++++++++++++++++++++--
  7. drivers/platform/x86/surfacepro3_button.c | 38 ++++++
  8. 2 files changed, 176 insertions(+), 13 deletions(-)
  9. diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
  10. index bb458beecb43..0cd942781bac 100644
  11. --- a/drivers/input/misc/soc_button_array.c
  12. +++ b/drivers/input/misc/soc_button_array.c
  13. @@ -29,6 +29,17 @@ struct soc_button_info {
  14. bool wakeup;
  15. };
  16. +/**
  17. + * struct soc_device_data - driver data for different device types
  18. + * @button_info: specifications of buttons, if NULL specification is assumed to
  19. + * be present in _DSD
  20. + * @check: device-specific check (NULL means all will be accepted)
  21. + */
  22. +struct soc_device_data {
  23. + struct soc_button_info *button_info;
  24. + int (*check)(struct device *dev);
  25. +};
  26. +
  27. /*
  28. * Some of the buttons like volume up/down are auto repeat, while others
  29. * are not. To support both, we register two platform devices, and put
  30. @@ -91,8 +102,12 @@ soc_button_device_create(struct platform_device *pdev,
  31. continue;
  32. gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
  33. - if (!gpio_is_valid(gpio))
  34. + if (gpio == -EPROBE_DEFER) {
  35. + error = -EPROBE_DEFER;
  36. + goto err_free_mem;
  37. + } else if (!gpio_is_valid(gpio)) {
  38. continue;
  39. + }
  40. gpio_keys[n_buttons].type = info->event_type;
  41. gpio_keys[n_buttons].code = info->event_code;
  42. @@ -314,6 +329,7 @@ static int soc_button_probe(struct platform_device *pdev)
  43. {
  44. struct device *dev = &pdev->dev;
  45. const struct acpi_device_id *id;
  46. + struct soc_device_data *device_data;
  47. struct soc_button_info *button_info;
  48. struct soc_button_data *priv;
  49. struct platform_device *pd;
  50. @@ -324,18 +340,20 @@ static int soc_button_probe(struct platform_device *pdev)
  51. if (!id)
  52. return -ENODEV;
  53. - if (!id->driver_data) {
  54. + device_data = (struct soc_device_data *)id->driver_data;
  55. + if (device_data && device_data->check) {
  56. + error = device_data->check(dev);
  57. + if (error)
  58. + return error;
  59. + }
  60. +
  61. + if (device_data && device_data->button_info) {
  62. + button_info = (struct soc_button_info *)
  63. + device_data->button_info;
  64. + } else {
  65. button_info = soc_button_get_button_info(dev);
  66. if (IS_ERR(button_info))
  67. return PTR_ERR(button_info);
  68. - } else {
  69. - button_info = (struct soc_button_info *)id->driver_data;
  70. - }
  71. -
  72. - error = gpiod_count(dev, NULL);
  73. - if (error < 0) {
  74. - dev_dbg(dev, "no GPIO attached, ignoring...\n");
  75. - return -ENODEV;
  76. }
  77. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  78. @@ -361,12 +379,32 @@ static int soc_button_probe(struct platform_device *pdev)
  79. if (!priv->children[0] && !priv->children[1])
  80. return -ENODEV;
  81. - if (!id->driver_data)
  82. + if (!device_data || !device_data->button_info)
  83. devm_kfree(dev, button_info);
  84. return 0;
  85. }
  86. +
  87. +static int soc_device_check_generic(struct device *dev)
  88. +{
  89. + int gpios;
  90. +
  91. + gpios = gpiod_count(dev, NULL);
  92. + if (gpios < 0) {
  93. + dev_dbg(dev, "no GPIO attached, ignoring...\n");
  94. + return -ENODEV;
  95. + }
  96. +
  97. + return 0;
  98. +}
  99. +
  100. +static struct soc_device_data soc_device_ACPI0011 = {
  101. + .button_info = NULL,
  102. + .check = soc_device_check_generic,
  103. +};
  104. +
  105. +
  106. /*
  107. * Definition of buttons on the tablet. The ACPI index of each button
  108. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  109. @@ -381,9 +419,96 @@ static struct soc_button_info soc_button_PNP0C40[] = {
  110. { }
  111. };
  112. +static struct soc_device_data soc_device_PNP0C40 = {
  113. + .button_info = soc_button_PNP0C40,
  114. + .check = soc_device_check_generic,
  115. +};
  116. +
  117. +
  118. +/*
  119. + * Special device check for Surface Book 2 and Surface Pro (2017).
  120. + * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  121. + * devices use MSHW0040 for power and volume buttons, however the way they
  122. + * have to be addressed differs. Make sure that we only load this drivers
  123. + * for the correct devices by checking the OEM Platform Revision provided by
  124. + * the _DSM method.
  125. + */
  126. +#define MSHW0040_DSM_REVISION 0x01
  127. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  128. +static const guid_t MSHW0040_DSM_UUID =
  129. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  130. + 0x49, 0x80, 0x35);
  131. +
  132. +#ifdef CONFIG_ACPI
  133. +
  134. +static int soc_device_check_MSHW0040(struct device *dev)
  135. +{
  136. + acpi_handle handle = ACPI_HANDLE(dev);
  137. + union acpi_object *result;
  138. + u64 oem_platform_rev = 0;
  139. + int gpios;
  140. +
  141. + // get OEM platform revision
  142. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  143. + MSHW0040_DSM_REVISION,
  144. + MSHW0040_DSM_GET_OMPR, NULL,
  145. + ACPI_TYPE_INTEGER);
  146. +
  147. + if (result) {
  148. + oem_platform_rev = result->integer.value;
  149. + ACPI_FREE(result);
  150. + }
  151. +
  152. + if (oem_platform_rev == 0)
  153. + return -ENODEV;
  154. +
  155. + dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  156. +
  157. + /*
  158. + * We are _really_ expecting GPIOs here. If we do not get any, this
  159. + * means the GPIO driver has not been loaded yet (which can happen).
  160. + * Try again later.
  161. + */
  162. + gpios = gpiod_count(dev, NULL);
  163. + if (gpios < 0)
  164. + return -EPROBE_DEFER;
  165. +
  166. + return 0;
  167. +}
  168. +
  169. +#else /* CONFIG_ACPI */
  170. +
  171. +static int soc_device_check_MSHW0040(struct device *dev)
  172. +{
  173. + return -ENODEV;
  174. +}
  175. +
  176. +#endif /* CONFIG_ACPI */
  177. +
  178. +/*
  179. + * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  180. + * Obtained from DSDT/testing.
  181. + */
  182. +static struct soc_button_info soc_button_MSHW0040[] = {
  183. + { "power", 0, EV_KEY, KEY_POWER, false, true },
  184. + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
  185. + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
  186. + { }
  187. +};
  188. +
  189. +static struct soc_device_data soc_device_MSHW0040 = {
  190. + .button_info = soc_button_MSHW0040,
  191. + .check = soc_device_check_MSHW0040,
  192. +};
  193. +
  194. +
  195. static const struct acpi_device_id soc_button_acpi_match[] = {
  196. - { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
  197. - { "ACPI0011", 0 },
  198. + { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  199. + { "ACPI0011", (unsigned long)&soc_device_ACPI0011 },
  200. +
  201. + /* Microsoft Surface Devices (5th and 6th generation) */
  202. + { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  203. +
  204. { }
  205. };
  206. diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
  207. index 1b491690ce07..eaec30380b11 100644
  208. --- a/drivers/platform/x86/surfacepro3_button.c
  209. +++ b/drivers/platform/x86/surfacepro3_button.c
  210. @@ -24,6 +24,12 @@
  211. #define SURFACE_BUTTON_OBJ_NAME "VGBI"
  212. #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
  213. +#define MSHW0040_DSM_REVISION 0x01
  214. +#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  215. +static const guid_t MSHW0040_DSM_UUID =
  216. + GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  217. + 0x49, 0x80, 0x35);
  218. +
  219. #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
  220. #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
  221. @@ -146,6 +152,34 @@ static int surface_button_resume(struct device *dev)
  222. }
  223. #endif
  224. +/*
  225. + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
  226. + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
  227. + * device by checking for the _DSM method and OEM Platform Revision.
  228. + */
  229. +static int surface_button_check_MSHW0040(struct acpi_device *dev)
  230. +{
  231. + acpi_handle handle = dev->handle;
  232. + union acpi_object *result;
  233. + u64 oem_platform_rev = 0;
  234. +
  235. + // get OEM platform revision
  236. + result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  237. + MSHW0040_DSM_REVISION,
  238. + MSHW0040_DSM_GET_OMPR,
  239. + NULL, ACPI_TYPE_INTEGER);
  240. +
  241. + if (result) {
  242. + oem_platform_rev = result->integer.value;
  243. + ACPI_FREE(result);
  244. + }
  245. +
  246. + dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  247. +
  248. + return oem_platform_rev == 0 ? 0 : -ENODEV;
  249. +}
  250. +
  251. +
  252. static int surface_button_add(struct acpi_device *device)
  253. {
  254. struct surface_button *button;
  255. @@ -158,6 +192,10 @@ static int surface_button_add(struct acpi_device *device)
  256. strlen(SURFACE_BUTTON_OBJ_NAME)))
  257. return -ENODEV;
  258. + error = surface_button_check_MSHW0040(device);
  259. + if (error)
  260. + return error;
  261. +
  262. button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
  263. if (!button)
  264. return -ENOMEM;
  265. --
  266. 2.22.0