soc_button_array.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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 == 0xca) {
  269. info->name = "rotation lock switch";
  270. info->event_type = EV_SW;
  271. info->event_code = SW_ROTATE_LOCK;
  272. } else if (upage == 0x07 && usage == 0xe3) {
  273. info->name = "home";
  274. info->event_code = KEY_LEFTMETA;
  275. info->wakeup = true;
  276. } else if (upage == 0x0c && usage == 0xe9) {
  277. info->name = "volume_up";
  278. info->event_code = KEY_VOLUMEUP;
  279. info->autorepeat = true;
  280. } else if (upage == 0x0c && usage == 0xea) {
  281. info->name = "volume_down";
  282. info->event_code = KEY_VOLUMEDOWN;
  283. info->autorepeat = true;
  284. } else {
  285. dev_warn(dev, "Unknown button index %d upage %02x usage %02x, ignoring\n",
  286. info->acpi_index, upage, usage);
  287. info->name = "unknown";
  288. info->event_code = KEY_RESERVED;
  289. }
  290. return 0;
  291. }
  292. /* ACPI0011 _DSD btns descriptors UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e */
  293. static const u8 btns_desc_uuid[16] = {
  294. 0x25, 0xd6, 0x6b, 0xfa, 0xe8, 0x9c, 0x0d, 0x47,
  295. 0xa2, 0xc7, 0xb3, 0xca, 0x36, 0xc4, 0x28, 0x2e
  296. };
  297. /* Parse ACPI0011 _DSD button descriptors */
  298. static struct soc_button_info *soc_button_get_button_info(struct device *dev)
  299. {
  300. struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
  301. const union acpi_object *desc, *el0, *uuid, *btns_desc = NULL;
  302. struct soc_button_info *button_info;
  303. acpi_status status;
  304. int i, btn, collection_uid = -1;
  305. status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL,
  306. &buf, ACPI_TYPE_PACKAGE);
  307. if (ACPI_FAILURE(status)) {
  308. dev_err(dev, "ACPI _DSD object not found\n");
  309. return ERR_PTR(-ENODEV);
  310. }
  311. /* Look for the Button Descriptors UUID */
  312. desc = buf.pointer;
  313. for (i = 0; (i + 1) < desc->package.count; i += 2) {
  314. uuid = &desc->package.elements[i];
  315. if (uuid->type != ACPI_TYPE_BUFFER ||
  316. uuid->buffer.length != 16 ||
  317. desc->package.elements[i + 1].type != ACPI_TYPE_PACKAGE) {
  318. break;
  319. }
  320. if (memcmp(uuid->buffer.pointer, btns_desc_uuid, 16) == 0) {
  321. btns_desc = &desc->package.elements[i + 1];
  322. break;
  323. }
  324. }
  325. if (!btns_desc) {
  326. dev_err(dev, "ACPI Button Descriptors not found\n");
  327. button_info = ERR_PTR(-ENODEV);
  328. goto out;
  329. }
  330. /* The first package describes the collection */
  331. el0 = &btns_desc->package.elements[0];
  332. if (el0->type == ACPI_TYPE_PACKAGE &&
  333. el0->package.count == 5 &&
  334. /* First byte should be 0 (collection) */
  335. soc_button_get_acpi_object_int(&el0->package.elements[0]) == 0 &&
  336. /* Third byte should be 0 (top level collection) */
  337. soc_button_get_acpi_object_int(&el0->package.elements[2]) == 0) {
  338. collection_uid = soc_button_get_acpi_object_int(
  339. &el0->package.elements[1]);
  340. }
  341. if (collection_uid == -1) {
  342. dev_err(dev, "Invalid Button Collection Descriptor\n");
  343. button_info = ERR_PTR(-ENODEV);
  344. goto out;
  345. }
  346. /* There are package.count - 1 buttons + 1 terminating empty entry */
  347. button_info = devm_kcalloc(dev, btns_desc->package.count,
  348. sizeof(*button_info), GFP_KERNEL);
  349. if (!button_info) {
  350. button_info = ERR_PTR(-ENOMEM);
  351. goto out;
  352. }
  353. /* Parse the button descriptors */
  354. for (i = 1, btn = 0; i < btns_desc->package.count; i++, btn++) {
  355. if (soc_button_parse_btn_desc(dev,
  356. &btns_desc->package.elements[i],
  357. collection_uid,
  358. &button_info[btn])) {
  359. button_info = ERR_PTR(-ENODEV);
  360. goto out;
  361. }
  362. }
  363. out:
  364. kfree(buf.pointer);
  365. return button_info;
  366. }
  367. static int soc_button_remove(struct platform_device *pdev)
  368. {
  369. struct soc_button_data *priv = platform_get_drvdata(pdev);
  370. int i;
  371. for (i = 0; i < BUTTON_TYPES; i++)
  372. if (priv->children[i])
  373. platform_device_unregister(priv->children[i]);
  374. return 0;
  375. }
  376. static int soc_button_probe(struct platform_device *pdev)
  377. {
  378. struct device *dev = &pdev->dev;
  379. const struct soc_device_data *device_data;
  380. const struct soc_button_info *button_info;
  381. struct soc_button_data *priv;
  382. struct platform_device *pd;
  383. int i;
  384. int error;
  385. device_data = acpi_device_get_match_data(dev);
  386. if (device_data && device_data->check) {
  387. error = device_data->check(dev);
  388. if (error)
  389. return error;
  390. }
  391. if (device_data && device_data->button_info) {
  392. button_info = device_data->button_info;
  393. } else {
  394. button_info = soc_button_get_button_info(dev);
  395. if (IS_ERR(button_info))
  396. return PTR_ERR(button_info);
  397. }
  398. error = gpiod_count(dev, NULL);
  399. if (error < 0) {
  400. dev_dbg(dev, "no GPIO attached, ignoring...\n");
  401. return -ENODEV;
  402. }
  403. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  404. if (!priv)
  405. return -ENOMEM;
  406. platform_set_drvdata(pdev, priv);
  407. for (i = 0; i < BUTTON_TYPES; i++) {
  408. pd = soc_button_device_create(pdev, button_info, i == 0);
  409. if (IS_ERR(pd)) {
  410. error = PTR_ERR(pd);
  411. if (error != -ENODEV) {
  412. soc_button_remove(pdev);
  413. return error;
  414. }
  415. continue;
  416. }
  417. priv->children[i] = pd;
  418. }
  419. if (!priv->children[0] && !priv->children[1])
  420. return -ENODEV;
  421. if (!device_data || !device_data->button_info)
  422. devm_kfree(dev, button_info);
  423. return 0;
  424. }
  425. /*
  426. * Definition of buttons on the tablet. The ACPI index of each button
  427. * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
  428. * Platforms"
  429. */
  430. static const struct soc_button_info soc_button_PNP0C40[] = {
  431. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  432. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
  433. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  434. { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  435. { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
  436. { }
  437. };
  438. static const struct soc_device_data soc_device_PNP0C40 = {
  439. .button_info = soc_button_PNP0C40,
  440. };
  441. static const struct soc_button_info soc_button_INT33D3[] = {
  442. { "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
  443. { }
  444. };
  445. static const struct soc_device_data soc_device_INT33D3 = {
  446. .button_info = soc_button_INT33D3,
  447. };
  448. /*
  449. * Button info for Microsoft Surface 3 (non pro), this is indentical to
  450. * the PNP0C40 info except that the home button is active-high.
  451. *
  452. * The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom
  453. * version of the drivers/platform/x86/intel/hid.c 5 button array ACPI API
  454. * instead. A check() callback is not necessary though as the Surface 3 Pro
  455. * MSHW0028 ACPI device's resource table does not contain any GPIOs.
  456. */
  457. static const struct soc_button_info soc_button_MSHW0028[] = {
  458. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  459. { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
  460. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  461. { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  462. { }
  463. };
  464. static const struct soc_device_data soc_device_MSHW0028 = {
  465. .button_info = soc_button_MSHW0028,
  466. };
  467. /*
  468. * Special device check for Surface Book 2 and Surface Pro (2017).
  469. * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
  470. * devices use MSHW0040 for power and volume buttons, however the way they
  471. * have to be addressed differs. Make sure that we only load this drivers
  472. * for the correct devices by checking the OEM Platform Revision provided by
  473. * the _DSM method.
  474. */
  475. #define MSHW0040_DSM_REVISION 0x01
  476. #define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
  477. static const guid_t MSHW0040_DSM_UUID =
  478. GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
  479. 0x49, 0x80, 0x35);
  480. static int soc_device_check_MSHW0040(struct device *dev)
  481. {
  482. acpi_handle handle = ACPI_HANDLE(dev);
  483. union acpi_object *result;
  484. u64 oem_platform_rev = 0; // valid revisions are nonzero
  485. // get OEM platform revision
  486. result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
  487. MSHW0040_DSM_REVISION,
  488. MSHW0040_DSM_GET_OMPR, NULL,
  489. ACPI_TYPE_INTEGER);
  490. if (result) {
  491. oem_platform_rev = result->integer.value;
  492. ACPI_FREE(result);
  493. }
  494. /*
  495. * If the revision is zero here, the _DSM evaluation has failed. This
  496. * indicates that we have a Pro 4 or Book 1 and this driver should not
  497. * be used.
  498. */
  499. if (oem_platform_rev == 0)
  500. return -ENODEV;
  501. dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
  502. return 0;
  503. }
  504. /*
  505. * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
  506. * Obtained from DSDT/testing.
  507. */
  508. static const struct soc_button_info soc_button_MSHW0040[] = {
  509. { "power", 0, EV_KEY, KEY_POWER, false, true, true },
  510. { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
  511. { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
  512. { }
  513. };
  514. static const struct soc_device_data soc_device_MSHW0040 = {
  515. .button_info = soc_button_MSHW0040,
  516. .check = soc_device_check_MSHW0040,
  517. };
  518. static const struct acpi_device_id soc_button_acpi_match[] = {
  519. { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
  520. { "INT33D3", (unsigned long)&soc_device_INT33D3 },
  521. { "ID9001", (unsigned long)&soc_device_INT33D3 },
  522. { "ACPI0011", 0 },
  523. /* Microsoft Surface Devices (3th, 5th and 6th generation) */
  524. { "MSHW0028", (unsigned long)&soc_device_MSHW0028 },
  525. { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
  526. { }
  527. };
  528. MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
  529. static struct platform_driver soc_button_driver = {
  530. .probe = soc_button_probe,
  531. .remove = soc_button_remove,
  532. .driver = {
  533. .name = KBUILD_MODNAME,
  534. .acpi_match_table = ACPI_PTR(soc_button_acpi_match),
  535. },
  536. };
  537. module_platform_driver(soc_button_driver);
  538. MODULE_LICENSE("GPL");