soc_button_array.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Supports for the button array on SoC tablets originally running
  4. * Windows 8.
  5. *
  6. * (C) Copyright 2014 Intel Corporation
  7. */
  8. #include <linux/module.h>
  9. #include <linux/input.h>
  10. #include <linux/init.h>
  11. #include <linux/irq.h>
  12. #include <linux/kernel.h>
  13. #include <linux/acpi.h>
  14. #include <linux/dmi.h>
  15. #include <linux/gpio/consumer.h>
  16. #include <linux/gpio_keys.h>
  17. #include <linux/gpio.h>
  18. #include <linux/platform_device.h>
  19. static bool use_low_level_irq;
  20. module_param(use_low_level_irq, bool, 0444);
  21. MODULE_PARM_DESC(use_low_level_irq, "Use low-level triggered IRQ instead of edge triggered");
  22. struct soc_button_info {
  23. const char *name;
  24. int acpi_index;
  25. unsigned int event_type;
  26. unsigned int event_code;
  27. bool autorepeat;
  28. bool wakeup;
  29. bool active_low;
  30. };
  31. struct soc_device_data {
  32. const struct soc_button_info *button_info;
  33. int (*check)(struct device *dev);
  34. };
  35. /*
  36. * Some of the buttons like volume up/down are auto repeat, while others
  37. * are not. To support both, we register two platform devices, and put
  38. * buttons into them based on whether the key should be auto repeat.
  39. */
  40. #define BUTTON_TYPES 2
  41. struct soc_button_data {
  42. struct platform_device *children[BUTTON_TYPES];
  43. };
  44. /*
  45. * Some 2-in-1s which use the soc_button_array driver have this ugly issue in
  46. * their DSDT where the _LID method modifies the irq-type settings of the GPIOs
  47. * used for the power and home buttons. The intend of this AML code is to
  48. * disable these buttons when the lid is closed.
  49. * The AML does this by directly poking the GPIO controllers registers. This is
  50. * problematic because when re-enabling the irq, which happens whenever _LID
  51. * gets called with the lid open (e.g. on boot and on resume), it sets the
  52. * irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the
  53. * type to, and expects it to be, IRQ_TYPE_EDGE_BOTH.
  54. * To work around this we don't set gpio_keys_button.gpio on these 2-in-1s,
  55. * instead we get the irq for the GPIO ourselves, configure it as
  56. * IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass
  57. * the irq in gpio_keys_button.irq. Below is a list of affected devices.
  58. */
  59. static const struct dmi_system_id dmi_use_low_level_irq[] = {
  60. {
  61. /*
  62. * Acer Switch 10 SW5-012. _LID method messes with home- and
  63. * power-button GPIO IRQ settings. When (re-)enabling the irq
  64. * it ors in its own flags without clearing the previous set
  65. * ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW |
  66. * IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm.
  67. */
  68. .matches = {
  69. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  70. DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
  71. },
  72. },
  73. {
  74. /* Acer Switch V 10 SW5-017, same issue as Acer Switch 10 SW5-012. */
  75. .matches = {
  76. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  77. DMI_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
  78. },
  79. },
  80. {
  81. /*
  82. * Acer One S1003. _LID method messes with power-button GPIO
  83. * IRQ settings, leading to a non working power-button.
  84. */
  85. .matches = {
  86. DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
  87. DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"),
  88. },
  89. },
  90. {
  91. /*
  92. * Lenovo Yoga Tab2 1051F/1051L, something messes with the home-button
  93. * IRQ settings, leading to a non working home-button.
  94. */
  95. .matches = {
  96. DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
  97. DMI_MATCH(DMI_PRODUCT_NAME, "60073"),
  98. DMI_MATCH(DMI_PRODUCT_VERSION, "1051"),
  99. },
  100. },
  101. {} /* Terminating entry */
  102. };
  103. /*
  104. * Some devices have a wrong entry which points to a GPIO which is
  105. * required in another driver, so this driver must not claim it.
  106. */
  107. static const struct dmi_system_id dmi_invalid_acpi_index[] = {
  108. {
  109. /*
  110. * Lenovo Yoga Book X90F / X90L, the PNP0C40 home button entry
  111. * points to a GPIO which is not a home button and which is
  112. * required by the lenovo-yogabook driver.
  113. */
  114. .matches = {
  115. DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
  116. DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
  117. DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
  118. },
  119. .driver_data = (void *)1l,
  120. },
  121. {} /* Terminating entry */
  122. };
  123. /*
  124. * Get the Nth GPIO number from the ACPI object.
  125. */
  126. static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
  127. int *gpio_ret, int *irq_ret)
  128. {
  129. struct gpio_desc *desc;
  130. desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
  131. if (IS_ERR(desc))
  132. return PTR_ERR(desc);
  133. *gpio_ret = desc_to_gpio(desc);
  134. *irq_ret = gpiod_to_irq(desc);
  135. gpiod_put(desc);
  136. return 0;
  137. }
  138. static struct platform_device *
  139. soc_button_device_create(struct platform_device *pdev,
  140. const struct soc_button_info *button_info,
  141. bool autorepeat)
  142. {
  143. const struct soc_button_info *info;
  144. struct platform_device *pd;
  145. struct gpio_keys_button *gpio_keys;
  146. struct gpio_keys_platform_data *gpio_keys_pdata;
  147. const struct dmi_system_id *dmi_id;
  148. int invalid_acpi_index = -1;
  149. int error, gpio, irq;
  150. int n_buttons = 0;
  151. for (info = button_info; info->name; info++)
  152. if (info->autorepeat == autorepeat)
  153. n_buttons++;
  154. gpio_keys_pdata = devm_kzalloc(&pdev->dev,
  155. sizeof(*gpio_keys_pdata) +
  156. sizeof(*gpio_keys) * n_buttons,
  157. GFP_KERNEL);
  158. if (!gpio_keys_pdata)
  159. return ERR_PTR(-ENOMEM);
  160. gpio_keys = (void *)(gpio_keys_pdata + 1);
  161. n_buttons = 0;
  162. dmi_id = dmi_first_match(dmi_invalid_acpi_index);
  163. if (dmi_id)
  164. invalid_acpi_index = (long)dmi_id->driver_data;
  165. for (info = button_info; info->name; info++) {
  166. if (info->autorepeat != autorepeat)
  167. continue;
  168. if (info->acpi_index == invalid_acpi_index)
  169. continue;
  170. error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
  171. if (error || irq < 0) {
  172. /*
  173. * Skip GPIO if not present. Note we deliberately
  174. * ignore -EPROBE_DEFER errors here. On some devices
  175. * Intel is using so called virtual GPIOs which are not
  176. * GPIOs at all but some way for AML code to check some
  177. * random status bits without need a custom opregion.
  178. * In some cases the resources table we parse points to
  179. * such a virtual GPIO, since these are not real GPIOs
  180. * we do not have a driver for these so they will never
  181. * show up, therefore we ignore -EPROBE_DEFER.
  182. */
  183. continue;
  184. }
  185. /* See dmi_use_low_level_irq[] comment */
  186. if (!autorepeat && (use_low_level_irq ||
  187. dmi_check_system(dmi_use_low_level_irq))) {
  188. irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
  189. gpio_keys[n_buttons].irq = irq;
  190. gpio_keys[n_buttons].gpio = -ENOENT;
  191. } else {
  192. gpio_keys[n_buttons].gpio = gpio;
  193. }
  194. gpio_keys[n_buttons].type = info->event_type;
  195. gpio_keys[n_buttons].code = info->event_code;
  196. gpio_keys[n_buttons].active_low = info->active_low;
  197. gpio_keys[n_buttons].desc = info->name;
  198. gpio_keys[n_buttons].wakeup = info->wakeup;
  199. /* These devices often use cheap buttons, use 50 ms debounce */
  200. gpio_keys[n_buttons].debounce_interval = 50;
  201. n_buttons++;
  202. }
  203. if (n_buttons == 0) {
  204. error = -ENODEV;
  205. goto err_free_mem;
  206. }
  207. gpio_keys_pdata->buttons = gpio_keys;
  208. gpio_keys_pdata->nbuttons = n_buttons;
  209. gpio_keys_pdata->rep = autorepeat;
  210. pd = platform_device_register_resndata(&pdev->dev, "gpio-keys",
  211. PLATFORM_DEVID_AUTO, NULL, 0,
  212. gpio_keys_pdata,
  213. sizeof(*gpio_keys_pdata));
  214. error = PTR_ERR_OR_ZERO(pd);
  215. if (error) {
  216. dev_err(&pdev->dev,
  217. "failed registering gpio-keys: %d\n", error);
  218. goto err_free_mem;
  219. }
  220. return pd;
  221. err_free_mem:
  222. devm_kfree(&pdev->dev, gpio_keys_pdata);
  223. return ERR_PTR(error);
  224. }
  225. static int soc_button_get_acpi_object_int(const union acpi_object *obj)
  226. {
  227. if (obj->type != ACPI_TYPE_INTEGER)
  228. return -1;
  229. return obj->integer.value;
  230. }
  231. /* Parse a single ACPI0011 _DSD button descriptor */
  232. static int soc_button_parse_btn_desc(struct device *dev,
  233. const union acpi_object *desc,
  234. int collection_uid,
  235. struct soc_button_info *info)
  236. {
  237. int upage, usage;
  238. if (desc->type != ACPI_TYPE_PACKAGE ||
  239. desc->package.count != 5 ||
  240. /* First byte should be 1 (control) */
  241. soc_button_get_acpi_object_int(&desc->package.elements[0]) != 1 ||
  242. /* Third byte should be collection uid */
  243. soc_button_get_acpi_object_int(&desc->package.elements[2]) !=
  244. collection_uid) {
  245. dev_err(dev, "Invalid ACPI Button Descriptor\n");
  246. return -ENODEV;
  247. }
  248. info->event_type = EV_KEY;
  249. info->active_low = true;
  250. info->acpi_index =
  251. soc_button_get_acpi_object_int(&desc->package.elements[1]);
  252. upage = soc_button_get_acpi_object_int(&desc->package.elements[3]);
  253. usage = soc_button_get_acpi_object_int(&desc->package.elements[4]);
  254. /*
  255. * The UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e descriptors use HID
  256. * usage page and usage codes, but otherwise the device is not HID
  257. * compliant: it uses one irq per button instead of generating HID
  258. * input reports and some buttons should generate wakeups where as
  259. * others should not, so we cannot use the HID subsystem.
  260. *
  261. * Luckily all devices only use a few usage page + usage combinations,
  262. * so we can simply check for the known combinations here.
  263. */
  264. if (upage == 0x01 && usage == 0x81) {
  265. info->name = "power";
  266. info->event_code = KEY_POWER;
  267. info->wakeup = true;
  268. } else if (upage == 0x01 && usage == 0xc6) {
  269. info->name = "airplane mode switch";
  270. info->event_type = EV_SW;
  271. info->event_code = SW_RFKILL_ALL;
  272. info->active_low = false;
  273. } else if (upage == 0x01 && usage == 0xca) {
  274. info->name = "rotation lock switch";
  275. info->event_type = EV_SW;
  276. info->event_code = SW_ROTATE_LOCK;
  277. } else if (upage == 0x07 && usage == 0xe3) {
  278. info->name = "home";
  279. info->event_code = KEY_LEFTMETA;
  280. info->wakeup = true;
  281. } else if (upage == 0x0c && usage == 0xe9) {
  282. info->name = "volume_up";
  283. info->event_code = KEY_VOLUMEUP;
  284. info->autorepeat = true;
  285. } else if (upage == 0x0c && usage == 0xea) {
  286. info->name = "volume_down";
  287. info->event_code = KEY_VOLUMEDOWN;
  288. info->autorepeat = true;
  289. } else {
  290. dev_warn(dev, "Unknown button index %d upage %02x usage %02x, ignoring\n",
  291. info->acpi_index, upage, usage);
  292. info->name = "unknown";
  293. info->event_code = KEY_RESERVED;
  294. }
  295. return 0;
  296. }
  297. /* ACPI0011 _DSD btns descriptors UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e */
  298. static const u8 btns_desc_uuid[16] = {
  299. 0x25, 0xd6, 0x6b, 0xfa, 0xe8, 0x9c, 0x0d, 0x47,
  300. 0xa2, 0xc7, 0xb3, 0xca, 0x36, 0xc4, 0x28, 0x2e
  301. };
  302. /* Parse ACPI0011 _DSD button descriptors */
  303. static struct soc_button_info *soc_button_get_button_info(struct device *dev)
  304. {
  305. struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
  306. const union acpi_object *desc, *el0, *uuid, *btns_desc = NULL;
  307. struct soc_button_info *button_info;
  308. acpi_status status;
  309. int i, btn, collection_uid = -1;
  310. status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL,
  311. &buf, ACPI_TYPE_PACKAGE);
  312. if (ACPI_FAILURE(status)) {
  313. dev_err(dev, "ACPI _DSD object not found\n");
  314. return ERR_PTR(-ENODEV);
  315. }
  316. /* Look for the Button Descriptors UUID */
  317. desc = buf.pointer;
  318. for (i = 0; (i + 1) < desc->package.count; i += 2) {
  319. uuid = &desc->package.elements[i];
  320. if (uuid->type != ACPI_TYPE_BUFFER ||
  321. uuid->buffer.length != 16 ||
  322. desc->package.elements[i + 1].type != ACPI_TYPE_PACKAGE) {
  323. break;
  324. }
  325. if (memcmp(uuid->buffer.pointer, btns_desc_uuid, 16) == 0) {
  326. btns_desc = &desc->package.elements[i + 1];
  327. break;
  328. }
  329. }
  330. if (!btns_desc) {
  331. dev_err(dev, "ACPI Button Descriptors not found\n");
  332. button_info = ERR_PTR(-ENODEV);
  333. goto out;
  334. }
  335. /* The first package describes the collection */
  336. el0 = &btns_desc->package.elements[0];
  337. if (el0->type == ACPI_TYPE_PACKAGE &&
  338. el0->package.count == 5 &&
  339. /* First byte should be 0 (collection) */
  340. soc_button_get_acpi_object_int(&el0->package.elements[0]) == 0 &&
  341. /* Third byte should be 0 (top level collection) */
  342. soc_button_get_acpi_object_int(&el0->package.elements[2]) == 0) {
  343. collection_uid = soc_button_get_acpi_object_int(
  344. &el0->package.elements[1]);
  345. }
  346. if (collection_uid == -1) {
  347. dev_err(dev, "Invalid Button Collection Descriptor\n");
  348. button_info = ERR_PTR(-ENODEV);
  349. goto out;
  350. }
  351. /* There are package.count - 1 buttons + 1 terminating empty entry */
  352. button_info = devm_kcalloc(dev, btns_desc->package.count,
  353. sizeof(*button_info), GFP_KERNEL);
  354. if (!button_info) {
  355. button_info = ERR_PTR(-ENOMEM);
  356. goto out;
  357. }
  358. /* Parse the button descriptors */
  359. for (i = 1, btn = 0; i < btns_desc->package.count; i++, btn++) {
  360. if (soc_button_parse_btn_desc(dev,
  361. &btns_desc->package.elements[i],
  362. collection_uid,
  363. &button_info[btn])) {
  364. button_info = ERR_PTR(-ENODEV);
  365. goto out;
  366. }
  367. }
  368. out:
  369. kfree(buf.pointer);
  370. return button_info;
  371. }
  372. static void soc_button_remove(struct platform_device *pdev)
  373. {
  374. struct soc_button_data *priv = platform_get_drvdata(pdev);
  375. int i;
  376. for (i = 0; i < BUTTON_TYPES; i++)
  377. if (priv->children[i])
  378. platform_device_unregister(priv->children[i]);
  379. }
  380. static int soc_button_probe(struct platform_device *pdev)
  381. {
  382. struct device *dev = &pdev->dev;
  383. const struct soc_device_data *device_data;
  384. const struct soc_button_info *button_info;
  385. struct soc_button_data *priv;
  386. struct platform_device *pd;
  387. int i;
  388. int error;
  389. device_data = acpi_device_get_match_data(dev);
  390. if (device_data && device_data->check) {
  391. error = device_data->check(dev);
  392. if (error)
  393. return error;
  394. }
  395. if (device_data && device_data->button_info) {
  396. button_info = device_data->button_info;
  397. } else {
  398. button_info = soc_button_get_button_info(dev);
  399. if (IS_ERR(button_info))
  400. return PTR_ERR(button_info);
  401. }
  402. error = gpiod_count(dev, NULL);
  403. if (error < 0) {
  404. dev_dbg(dev, "no GPIO attached, ignoring...\n");
  405. return -ENODEV;
  406. }
  407. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  408. if (!priv)
  409. return -ENOMEM;
  410. platform_set_drvdata(pdev, priv);
  411. for (i = 0; i < BUTTON_TYPES; i++) {
  412. pd = soc_button_device_create(pdev, button_info, i == 0);
  413. if (IS_ERR(pd)) {
  414. error = PTR_ERR(pd);
  415. if (error != -ENODEV) {
  416. soc_button_remove(pdev);
  417. return error;
  418. }
  419. continue;
  420. }
  421. priv->children[i] = pd;
  422. }
  423. if (!priv->children[0] && !priv->children[1])
  424. return -ENODEV;
  425. if (!device_data || !device_data->button_info)
  426. devm_kfree(dev, button_info);
  427. return 0;
  428. }
  429. /*
  430. * Definition of buttons on the tablet. The ACPI index of each button
  431. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  432. * Platforms"
  433. */
  434. static const struct soc_button_info soc_button_PNP0C40[] = {
  435. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  436. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
  437. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  438. { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  439. { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
  440. { }
  441. };
  442. static const struct soc_device_data soc_device_PNP0C40 = {
  443. .button_info = soc_button_PNP0C40,
  444. };
  445. static const struct soc_button_info soc_button_INT33D3[] = {
  446. { "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
  447. { }
  448. };
  449. static const struct soc_device_data soc_device_INT33D3 = {
  450. .button_info = soc_button_INT33D3,
  451. };
  452. /*
  453. * Button info for Microsoft Surface 3 (non pro), this is indentical to
  454. * the PNP0C40 info except that the home button is active-high.
  455. *
  456. * The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom
  457. * version of the drivers/platform/x86/intel/hid.c 5 button array ACPI API
  458. * instead. A check() callback is not necessary though as the Surface 3 Pro
  459. * MSHW0028 ACPI device's resource table does not contain any GPIOs.
  460. */
  461. static const struct soc_button_info soc_button_MSHW0028[] = {
  462. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  463. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
  464. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  465. { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  466. { }
  467. };
  468. static const struct soc_device_data soc_device_MSHW0028 = {
  469. .button_info = soc_button_MSHW0028,
  470. };
  471. /*
  472. * Special device check for Surface Book 2 and Surface Pro (2017).
  473. * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  474. * devices use MSHW0040 for power and volume buttons, however the way they
  475. * have to be addressed differs. Make sure that we only load this drivers
  476. * for the correct devices by checking the OEM Platform Revision provided by
  477. * the _DSM method.
  478. */
  479. #define MSHW0040_DSM_REVISION 0x01
  480. #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  481. static const guid_t MSHW0040_DSM_UUID =
  482. GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  483. 0x49, 0x80, 0x35);
  484. static int soc_device_check_MSHW0040(struct device *dev)
  485. {
  486. acpi_handle handle = ACPI_HANDLE(dev);
  487. union acpi_object *result;
  488. u64 oem_platform_rev = 0; // valid revisions are nonzero
  489. // get OEM platform revision
  490. result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  491. MSHW0040_DSM_REVISION,
  492. MSHW0040_DSM_GET_OMPR, NULL,
  493. ACPI_TYPE_INTEGER);
  494. if (result) {
  495. oem_platform_rev = result->integer.value;
  496. ACPI_FREE(result);
  497. }
  498. /*
  499. * If the revision is zero here, the _DSM evaluation has failed. This
  500. * indicates that we have a Pro 4 or Book 1 and this driver should not
  501. * be used.
  502. */
  503. if (oem_platform_rev == 0)
  504. return -ENODEV;
  505. dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  506. return 0;
  507. }
  508. /*
  509. * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  510. * Obtained from DSDT/testing.
  511. */
  512. static const struct soc_button_info soc_button_MSHW0040[] = {
  513. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  514. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  515. { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  516. { }
  517. };
  518. static const struct soc_device_data soc_device_MSHW0040 = {
  519. .button_info = soc_button_MSHW0040,
  520. .check = soc_device_check_MSHW0040,
  521. };
  522. static const struct acpi_device_id soc_button_acpi_match[] = {
  523. { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  524. { "INT33D3", (unsigned long)&soc_device_INT33D3 },
  525. { "ID9001", (unsigned long)&soc_device_INT33D3 },
  526. { "ACPI0011", 0 },
  527. /* Microsoft Surface Devices (3th, 5th and 6th generation) */
  528. { "MSHW0028", (unsigned long)&soc_device_MSHW0028 },
  529. { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  530. { }
  531. };
  532. MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
  533. static struct platform_driver soc_button_driver = {
  534. .probe = soc_button_probe,
  535. .remove_new = soc_button_remove,
  536. .driver = {
  537. .name = KBUILD_MODNAME,
  538. .acpi_match_table = ACPI_PTR(soc_button_acpi_match),
  539. },
  540. };
  541. module_platform_driver(soc_button_driver);
  542. MODULE_DESCRIPTION("Windows-compatible SoC Button Array driver");
  543. MODULE_LICENSE("GPL");