hc
2024-05-14 bedbef8ad3e75a304af6361af235302bcc61d06b
kernel/drivers/input/misc/soc_button_array.c
....@@ -1,24 +1,26 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Supports for the button array on SoC tablets originally running
34 * Windows 8.
45 *
56 * (C) Copyright 2014 Intel Corporation
6
- *
7
- * This program is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU General Public License
9
- * as published by the Free Software Foundation; version 2
10
- * of the License.
117 */
128
139 #include <linux/module.h>
1410 #include <linux/input.h>
1511 #include <linux/init.h>
12
+#include <linux/irq.h>
1613 #include <linux/kernel.h>
1714 #include <linux/acpi.h>
15
+#include <linux/dmi.h>
1816 #include <linux/gpio/consumer.h>
1917 #include <linux/gpio_keys.h>
2018 #include <linux/gpio.h>
2119 #include <linux/platform_device.h>
20
+
21
+static bool use_low_level_irq;
22
+module_param(use_low_level_irq, bool, 0444);
23
+MODULE_PARM_DESC(use_low_level_irq, "Use low-level triggered IRQ instead of edge triggered");
2224
2325 struct soc_button_info {
2426 const char *name;
....@@ -27,6 +29,12 @@
2729 unsigned int event_code;
2830 bool autorepeat;
2931 bool wakeup;
32
+ bool active_low;
33
+};
34
+
35
+struct soc_device_data {
36
+ const struct soc_button_info *button_info;
37
+ int (*check)(struct device *dev);
3038 };
3139
3240 /*
....@@ -41,22 +49,104 @@
4149 };
4250
4351 /*
52
+ * Some 2-in-1s which use the soc_button_array driver have this ugly issue in
53
+ * their DSDT where the _LID method modifies the irq-type settings of the GPIOs
54
+ * used for the power and home buttons. The intend of this AML code is to
55
+ * disable these buttons when the lid is closed.
56
+ * The AML does this by directly poking the GPIO controllers registers. This is
57
+ * problematic because when re-enabling the irq, which happens whenever _LID
58
+ * gets called with the lid open (e.g. on boot and on resume), it sets the
59
+ * irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the
60
+ * type to, and expects it to be, IRQ_TYPE_EDGE_BOTH.
61
+ * To work around this we don't set gpio_keys_button.gpio on these 2-in-1s,
62
+ * instead we get the irq for the GPIO ourselves, configure it as
63
+ * IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass
64
+ * the irq in gpio_keys_button.irq. Below is a list of affected devices.
65
+ */
66
+static const struct dmi_system_id dmi_use_low_level_irq[] = {
67
+ {
68
+ /*
69
+ * Acer Switch 10 SW5-012. _LID method messes with home- and
70
+ * power-button GPIO IRQ settings. When (re-)enabling the irq
71
+ * it ors in its own flags without clearing the previous set
72
+ * ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW |
73
+ * IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm.
74
+ */
75
+ .matches = {
76
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
77
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
78
+ },
79
+ },
80
+ {
81
+ /* Acer Switch V 10 SW5-017, same issue as Acer Switch 10 SW5-012. */
82
+ .matches = {
83
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
84
+ DMI_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
85
+ },
86
+ },
87
+ {
88
+ /*
89
+ * Acer One S1003. _LID method messes with power-button GPIO
90
+ * IRQ settings, leading to a non working power-button.
91
+ */
92
+ .matches = {
93
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
94
+ DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"),
95
+ },
96
+ },
97
+ {
98
+ /*
99
+ * Lenovo Yoga Tab2 1051F/1051L, something messes with the home-button
100
+ * IRQ settings, leading to a non working home-button.
101
+ */
102
+ .matches = {
103
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
104
+ DMI_MATCH(DMI_PRODUCT_NAME, "60073"),
105
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1051"),
106
+ },
107
+ },
108
+ {} /* Terminating entry */
109
+};
110
+
111
+/*
112
+ * Some devices have a wrong entry which points to a GPIO which is
113
+ * required in another driver, so this driver must not claim it.
114
+ */
115
+static const struct dmi_system_id dmi_invalid_acpi_index[] = {
116
+ {
117
+ /*
118
+ * Lenovo Yoga Book X90F / X90L, the PNP0C40 home button entry
119
+ * points to a GPIO which is not a home button and which is
120
+ * required by the lenovo-yogabook driver.
121
+ */
122
+ .matches = {
123
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
124
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
125
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
126
+ },
127
+ .driver_data = (void *)1l,
128
+ },
129
+ {} /* Terminating entry */
130
+};
131
+
132
+/*
44133 * Get the Nth GPIO number from the ACPI object.
45134 */
46
-static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
135
+static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
136
+ int *gpio_ret, int *irq_ret)
47137 {
48138 struct gpio_desc *desc;
49
- int gpio;
50139
51140 desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
52141 if (IS_ERR(desc))
53142 return PTR_ERR(desc);
54143
55
- gpio = desc_to_gpio(desc);
144
+ *gpio_ret = desc_to_gpio(desc);
145
+ *irq_ret = gpiod_to_irq(desc);
56146
57147 gpiod_put(desc);
58148
59
- return gpio;
149
+ return 0;
60150 }
61151
62152 static struct platform_device *
....@@ -68,9 +158,10 @@
68158 struct platform_device *pd;
69159 struct gpio_keys_button *gpio_keys;
70160 struct gpio_keys_platform_data *gpio_keys_pdata;
161
+ const struct dmi_system_id *dmi_id;
162
+ int invalid_acpi_index = -1;
163
+ int error, gpio, irq;
71164 int n_buttons = 0;
72
- int gpio;
73
- int error;
74165
75166 for (info = button_info; info->name; info++)
76167 if (info->autorepeat == autorepeat)
....@@ -86,18 +177,46 @@
86177 gpio_keys = (void *)(gpio_keys_pdata + 1);
87178 n_buttons = 0;
88179
180
+ dmi_id = dmi_first_match(dmi_invalid_acpi_index);
181
+ if (dmi_id)
182
+ invalid_acpi_index = (long)dmi_id->driver_data;
183
+
89184 for (info = button_info; info->name; info++) {
90185 if (info->autorepeat != autorepeat)
91186 continue;
92187
93
- gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
94
- if (!gpio_is_valid(gpio))
188
+ if (info->acpi_index == invalid_acpi_index)
95189 continue;
190
+
191
+ error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
192
+ if (error || irq < 0) {
193
+ /*
194
+ * Skip GPIO if not present. Note we deliberately
195
+ * ignore -EPROBE_DEFER errors here. On some devices
196
+ * Intel is using so called virtual GPIOs which are not
197
+ * GPIOs at all but some way for AML code to check some
198
+ * random status bits without need a custom opregion.
199
+ * In some cases the resources table we parse points to
200
+ * such a virtual GPIO, since these are not real GPIOs
201
+ * we do not have a driver for these so they will never
202
+ * show up, therefore we ignore -EPROBE_DEFER.
203
+ */
204
+ continue;
205
+ }
206
+
207
+ /* See dmi_use_low_level_irq[] comment */
208
+ if (!autorepeat && (use_low_level_irq ||
209
+ dmi_check_system(dmi_use_low_level_irq))) {
210
+ irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
211
+ gpio_keys[n_buttons].irq = irq;
212
+ gpio_keys[n_buttons].gpio = -ENOENT;
213
+ } else {
214
+ gpio_keys[n_buttons].gpio = gpio;
215
+ }
96216
97217 gpio_keys[n_buttons].type = info->event_type;
98218 gpio_keys[n_buttons].code = info->event_code;
99
- gpio_keys[n_buttons].gpio = gpio;
100
- gpio_keys[n_buttons].active_low = 1;
219
+ gpio_keys[n_buttons].active_low = info->active_low;
101220 gpio_keys[n_buttons].desc = info->name;
102221 gpio_keys[n_buttons].wakeup = info->wakeup;
103222 /* These devices often use cheap buttons, use 50 ms debounce */
....@@ -114,25 +233,19 @@
114233 gpio_keys_pdata->nbuttons = n_buttons;
115234 gpio_keys_pdata->rep = autorepeat;
116235
117
- pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO);
118
- if (!pd) {
119
- error = -ENOMEM;
236
+ pd = platform_device_register_resndata(&pdev->dev, "gpio-keys",
237
+ PLATFORM_DEVID_AUTO, NULL, 0,
238
+ gpio_keys_pdata,
239
+ sizeof(*gpio_keys_pdata));
240
+ error = PTR_ERR_OR_ZERO(pd);
241
+ if (error) {
242
+ dev_err(&pdev->dev,
243
+ "failed registering gpio-keys: %d\n", error);
120244 goto err_free_mem;
121245 }
122246
123
- error = platform_device_add_data(pd, gpio_keys_pdata,
124
- sizeof(*gpio_keys_pdata));
125
- if (error)
126
- goto err_free_pdev;
127
-
128
- error = platform_device_add(pd);
129
- if (error)
130
- goto err_free_pdev;
131
-
132247 return pd;
133248
134
-err_free_pdev:
135
- platform_device_put(pd);
136249 err_free_mem:
137250 devm_kfree(&pdev->dev, gpio_keys_pdata);
138251 return ERR_PTR(error);
....@@ -166,6 +279,7 @@
166279 }
167280
168281 info->event_type = EV_KEY;
282
+ info->active_low = true;
169283 info->acpi_index =
170284 soc_button_get_acpi_object_int(&desc->package.elements[1]);
171285 upage = soc_button_get_acpi_object_int(&desc->package.elements[3]);
....@@ -185,6 +299,10 @@
185299 info->name = "power";
186300 info->event_code = KEY_POWER;
187301 info->wakeup = true;
302
+ } else if (upage == 0x01 && usage == 0xca) {
303
+ info->name = "rotation lock switch";
304
+ info->event_type = EV_SW;
305
+ info->event_code = SW_ROTATE_LOCK;
188306 } else if (upage == 0x07 && usage == 0xe3) {
189307 info->name = "home";
190308 info->event_code = KEY_LEFTMETA;
....@@ -309,23 +427,26 @@
309427 static int soc_button_probe(struct platform_device *pdev)
310428 {
311429 struct device *dev = &pdev->dev;
312
- const struct acpi_device_id *id;
313
- struct soc_button_info *button_info;
430
+ const struct soc_device_data *device_data;
431
+ const struct soc_button_info *button_info;
314432 struct soc_button_data *priv;
315433 struct platform_device *pd;
316434 int i;
317435 int error;
318436
319
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
320
- if (!id)
321
- return -ENODEV;
437
+ device_data = acpi_device_get_match_data(dev);
438
+ if (device_data && device_data->check) {
439
+ error = device_data->check(dev);
440
+ if (error)
441
+ return error;
442
+ }
322443
323
- if (!id->driver_data) {
444
+ if (device_data && device_data->button_info) {
445
+ button_info = device_data->button_info;
446
+ } else {
324447 button_info = soc_button_get_button_info(dev);
325448 if (IS_ERR(button_info))
326449 return PTR_ERR(button_info);
327
- } else {
328
- button_info = (struct soc_button_info *)id->driver_data;
329450 }
330451
331452 error = gpiod_count(dev, NULL);
....@@ -357,7 +478,7 @@
357478 if (!priv->children[0] && !priv->children[1])
358479 return -ENODEV;
359480
360
- if (!id->driver_data)
481
+ if (!device_data || !device_data->button_info)
361482 devm_kfree(dev, button_info);
362483
363484 return 0;
....@@ -368,18 +489,97 @@
368489 * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
369490 * Platforms"
370491 */
371
-static struct soc_button_info soc_button_PNP0C40[] = {
372
- { "power", 0, EV_KEY, KEY_POWER, false, true },
373
- { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
374
- { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
375
- { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
376
- { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false },
492
+static const struct soc_button_info soc_button_PNP0C40[] = {
493
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
494
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
495
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
496
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
497
+ { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
377498 { }
378499 };
379500
501
+static const struct soc_device_data soc_device_PNP0C40 = {
502
+ .button_info = soc_button_PNP0C40,
503
+};
504
+
505
+static const struct soc_button_info soc_button_INT33D3[] = {
506
+ { "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
507
+ { }
508
+};
509
+
510
+static const struct soc_device_data soc_device_INT33D3 = {
511
+ .button_info = soc_button_INT33D3,
512
+};
513
+
514
+/*
515
+ * Special device check for Surface Book 2 and Surface Pro (2017).
516
+ * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
517
+ * devices use MSHW0040 for power and volume buttons, however the way they
518
+ * have to be addressed differs. Make sure that we only load this drivers
519
+ * for the correct devices by checking the OEM Platform Revision provided by
520
+ * the _DSM method.
521
+ */
522
+#define MSHW0040_DSM_REVISION 0x01
523
+#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
524
+static const guid_t MSHW0040_DSM_UUID =
525
+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
526
+ 0x49, 0x80, 0x35);
527
+
528
+static int soc_device_check_MSHW0040(struct device *dev)
529
+{
530
+ acpi_handle handle = ACPI_HANDLE(dev);
531
+ union acpi_object *result;
532
+ u64 oem_platform_rev = 0; // valid revisions are nonzero
533
+
534
+ // get OEM platform revision
535
+ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
536
+ MSHW0040_DSM_REVISION,
537
+ MSHW0040_DSM_GET_OMPR, NULL,
538
+ ACPI_TYPE_INTEGER);
539
+
540
+ if (result) {
541
+ oem_platform_rev = result->integer.value;
542
+ ACPI_FREE(result);
543
+ }
544
+
545
+ /*
546
+ * If the revision is zero here, the _DSM evaluation has failed. This
547
+ * indicates that we have a Pro 4 or Book 1 and this driver should not
548
+ * be used.
549
+ */
550
+ if (oem_platform_rev == 0)
551
+ return -ENODEV;
552
+
553
+ dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
554
+
555
+ return 0;
556
+}
557
+
558
+/*
559
+ * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
560
+ * Obtained from DSDT/testing.
561
+ */
562
+static const struct soc_button_info soc_button_MSHW0040[] = {
563
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
564
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
565
+ { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
566
+ { }
567
+};
568
+
569
+static const struct soc_device_data soc_device_MSHW0040 = {
570
+ .button_info = soc_button_MSHW0040,
571
+ .check = soc_device_check_MSHW0040,
572
+};
573
+
380574 static const struct acpi_device_id soc_button_acpi_match[] = {
381
- { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
575
+ { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
576
+ { "INT33D3", (unsigned long)&soc_device_INT33D3 },
577
+ { "ID9001", (unsigned long)&soc_device_INT33D3 },
382578 { "ACPI0011", 0 },
579
+
580
+ /* Microsoft Surface Devices (5th and 6th generation) */
581
+ { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
582
+
383583 { }
384584 };
385585