]> Git Repo - linux.git/blob - drivers/platform/x86/x86-android-tablets/other.c
Merge tag 'core-debugobjects-2023-05-06' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / platform / x86 / x86-android-tablets / other.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * DMI based code to deal with broken DSDTs on X86 tablets which ship with
4  * Android as (part of) the factory image. The factory kernels shipped on these
5  * devices typically have a bunch of things hardcoded, rather than specified
6  * in their DSDT.
7  *
8  * Copyright (C) 2021-2023 Hans de Goede <[email protected]>
9  */
10
11 #include <linux/acpi.h>
12 #include <linux/gpio/machine.h>
13 #include <linux/input.h>
14 #include <linux/platform_device.h>
15
16 #include "shared-psy-info.h"
17 #include "x86-android-tablets.h"
18
19 /* Acer Iconia One 7 B1-750 has an Android factory img with everything hardcoded */
20 static const char * const acer_b1_750_mount_matrix[] = {
21         "-1", "0", "0",
22         "0", "1", "0",
23         "0", "0", "1"
24 };
25
26 static const struct property_entry acer_b1_750_bma250e_props[] = {
27         PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),
28         { }
29 };
30
31 static const struct software_node acer_b1_750_bma250e_node = {
32         .properties = acer_b1_750_bma250e_props,
33 };
34
35 static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {
36         {
37                 /* Novatek NVT-ts touchscreen */
38                 .board_info = {
39                         .type = "NVT-ts",
40                         .addr = 0x34,
41                         .dev_name = "NVT-ts",
42                 },
43                 .adapter_path = "\\_SB_.I2C4",
44                 .irq_data = {
45                         .type = X86_ACPI_IRQ_TYPE_GPIOINT,
46                         .chip = "INT33FC:02",
47                         .index = 3,
48                         .trigger = ACPI_EDGE_SENSITIVE,
49                         .polarity = ACPI_ACTIVE_LOW,
50                 },
51         }, {
52                 /* BMA250E accelerometer */
53                 .board_info = {
54                         .type = "bma250e",
55                         .addr = 0x18,
56                         .swnode = &acer_b1_750_bma250e_node,
57                 },
58                 .adapter_path = "\\_SB_.I2C3",
59                 .irq_data = {
60                         .type = X86_ACPI_IRQ_TYPE_GPIOINT,
61                         .chip = "INT33FC:02",
62                         .index = 25,
63                         .trigger = ACPI_LEVEL_SENSITIVE,
64                         .polarity = ACPI_ACTIVE_HIGH,
65                 },
66         },
67 };
68
69 static struct gpiod_lookup_table acer_b1_750_goodix_gpios = {
70         .dev_id = "i2c-NVT-ts",
71         .table = {
72                 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
73                 { }
74         },
75 };
76
77 static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
78         &acer_b1_750_goodix_gpios,
79         &int3496_reference_gpios,
80         NULL
81 };
82
83 const struct x86_dev_info acer_b1_750_info __initconst = {
84         .i2c_client_info = acer_b1_750_i2c_clients,
85         .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients),
86         .pdev_info = int3496_pdevs,
87         .pdev_count = 1,
88         .gpiod_lookup_tables = acer_b1_750_gpios,
89 };
90
91 /*
92  * Advantech MICA-071
93  * This is a standard Windows tablet, but it has an extra "quick launch" button
94  * which is not described in the ACPI tables in anyway.
95  * Use the x86-android-tablets infra to create a gpio-button device for this.
96  */
97 static struct x86_gpio_button advantech_mica_071_button = {
98         .button = {
99                 .code = KEY_PROG1,
100                 .active_low = true,
101                 .desc = "prog1_key",
102                 .type = EV_KEY,
103                 .wakeup = false,
104                 .debounce_interval = 50,
105         },
106         .chip = "INT33FC:00",
107         .pin = 2,
108 };
109
110 const struct x86_dev_info advantech_mica_071_info __initconst = {
111         .gpio_button = &advantech_mica_071_button,
112 };
113
114 /*
115  * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT
116  * contains a whole bunch of bogus ACPI I2C devices and is missing entries
117  * for the touchscreen and the accelerometer.
118  */
119 static const struct property_entry chuwi_hi8_gsl1680_props[] = {
120         PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
121         PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
122         PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
123         PROPERTY_ENTRY_BOOL("silead,home-button"),
124         PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
125         { }
126 };
127
128 static const struct software_node chuwi_hi8_gsl1680_node = {
129         .properties = chuwi_hi8_gsl1680_props,
130 };
131
132 static const char * const chuwi_hi8_mount_matrix[] = {
133         "1", "0", "0",
134         "0", "-1", "0",
135         "0", "0", "1"
136 };
137
138 static const struct property_entry chuwi_hi8_bma250e_props[] = {
139         PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
140         { }
141 };
142
143 static const struct software_node chuwi_hi8_bma250e_node = {
144         .properties = chuwi_hi8_bma250e_props,
145 };
146
147 static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
148         {
149                 /* Silead touchscreen */
150                 .board_info = {
151                         .type = "gsl1680",
152                         .addr = 0x40,
153                         .swnode = &chuwi_hi8_gsl1680_node,
154                 },
155                 .adapter_path = "\\_SB_.I2C4",
156                 .irq_data = {
157                         .type = X86_ACPI_IRQ_TYPE_APIC,
158                         .index = 0x44,
159                         .trigger = ACPI_EDGE_SENSITIVE,
160                         .polarity = ACPI_ACTIVE_HIGH,
161                 },
162         }, {
163                 /* BMA250E accelerometer */
164                 .board_info = {
165                         .type = "bma250e",
166                         .addr = 0x18,
167                         .swnode = &chuwi_hi8_bma250e_node,
168                 },
169                 .adapter_path = "\\_SB_.I2C3",
170                 .irq_data = {
171                         .type = X86_ACPI_IRQ_TYPE_GPIOINT,
172                         .chip = "INT33FC:02",
173                         .index = 23,
174                         .trigger = ACPI_LEVEL_SENSITIVE,
175                         .polarity = ACPI_ACTIVE_HIGH,
176                 },
177         },
178 };
179
180 static int __init chuwi_hi8_init(void)
181 {
182         /*
183          * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
184          * breaking the touchscreen + logging various errors when the Windows
185          * BIOS is used.
186          */
187         if (acpi_dev_present("MSSL0001", NULL, 1))
188                 return -ENODEV;
189
190         return 0;
191 }
192
193 const struct x86_dev_info chuwi_hi8_info __initconst = {
194         .i2c_client_info = chuwi_hi8_i2c_clients,
195         .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
196         .init = chuwi_hi8_init,
197 };
198
199 #define CZC_EC_EXTRA_PORT       0x68
200 #define CZC_EC_ANDROID_KEYS     0x63
201
202 static int __init czc_p10t_init(void)
203 {
204         /*
205          * The device boots up in "Windows 7" mode, when the home button sends a
206          * Windows specific key sequence (Left Meta + D) and the second button
207          * sends an unknown one while also toggling the Radio Kill Switch.
208          * This is a surprising behavior when the second button is labeled "Back".
209          *
210          * The vendor-supplied Android-x86 build switches the device to a "Android"
211          * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
212          * set bit 6 on address 0x96 in the EC region; switching the bit directly
213          * seems to achieve the same result. It uses a "p10t_switcher" to do the
214          * job. It doesn't seem to be able to do anything else, and no other use
215          * of the port 0x68 is known.
216          *
217          * In the Android mode, the home button sends just a single scancode,
218          * which can be handled in Linux userspace more reasonably and the back
219          * button only sends a scancode without toggling the kill switch.
220          * The scancode can then be mapped either to Back or RF Kill functionality
221          * in userspace, depending on how the button is labeled on that particular
222          * model.
223          */
224         outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
225         return 0;
226 }
227
228 const struct x86_dev_info czc_p10t __initconst = {
229         .init = czc_p10t_init,
230 };
231
232 /* Medion Lifetab S10346 tablets have an Android factory img with everything hardcoded */
233 static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
234         "0", "1", "0",
235         "1", "0", "0",
236         "0", "0", "1"
237 };
238
239 static const struct property_entry medion_lifetab_s10346_accel_props[] = {
240         PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
241         { }
242 };
243
244 static const struct software_node medion_lifetab_s10346_accel_node = {
245         .properties = medion_lifetab_s10346_accel_props,
246 };
247
248 /* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
249 static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
250         PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
251         PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
252         { }
253 };
254
255 static const struct software_node medion_lifetab_s10346_touchscreen_node = {
256         .properties = medion_lifetab_s10346_touchscreen_props,
257 };
258
259 static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
260         {
261                 /* kxtj21009 accel */
262                 .board_info = {
263                         .type = "kxtj21009",
264                         .addr = 0x0f,
265                         .dev_name = "kxtj21009",
266                         .swnode = &medion_lifetab_s10346_accel_node,
267                 },
268                 .adapter_path = "\\_SB_.I2C3",
269                 .irq_data = {
270                         .type = X86_ACPI_IRQ_TYPE_GPIOINT,
271                         .chip = "INT33FC:02",
272                         .index = 23,
273                         .trigger = ACPI_EDGE_SENSITIVE,
274                         .polarity = ACPI_ACTIVE_HIGH,
275                 },
276         }, {
277                 /* goodix touchscreen */
278                 .board_info = {
279                         .type = "GDIX1001:00",
280                         .addr = 0x14,
281                         .dev_name = "goodix_ts",
282                         .swnode = &medion_lifetab_s10346_touchscreen_node,
283                 },
284                 .adapter_path = "\\_SB_.I2C4",
285                 .irq_data = {
286                         .type = X86_ACPI_IRQ_TYPE_APIC,
287                         .index = 0x44,
288                         .trigger = ACPI_EDGE_SENSITIVE,
289                         .polarity = ACPI_ACTIVE_LOW,
290                 },
291         },
292 };
293
294 static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
295         .dev_id = "i2c-goodix_ts",
296         .table = {
297                 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
298                 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
299                 { }
300         },
301 };
302
303 static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
304         &medion_lifetab_s10346_goodix_gpios,
305         NULL
306 };
307
308 const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
309         .i2c_client_info = medion_lifetab_s10346_i2c_clients,
310         .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
311         .gpiod_lookup_tables = medion_lifetab_s10346_gpios,
312 };
313
314 /* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */
315 static const char * const nextbook_ares8_accel_mount_matrix[] = {
316         "0", "-1", "0",
317         "-1", "0", "0",
318         "0", "0", "1"
319 };
320
321 static const struct property_entry nextbook_ares8_accel_props[] = {
322         PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
323         { }
324 };
325
326 static const struct software_node nextbook_ares8_accel_node = {
327         .properties = nextbook_ares8_accel_props,
328 };
329
330 static const struct property_entry nextbook_ares8_touchscreen_props[] = {
331         PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
332         PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
333         { }
334 };
335
336 static const struct software_node nextbook_ares8_touchscreen_node = {
337         .properties = nextbook_ares8_touchscreen_props,
338 };
339
340 static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
341         {
342                 /* Freescale MMA8653FC accel */
343                 .board_info = {
344                         .type = "mma8653",
345                         .addr = 0x1d,
346                         .dev_name = "mma8653",
347                         .swnode = &nextbook_ares8_accel_node,
348                 },
349                 .adapter_path = "\\_SB_.I2C3",
350         }, {
351                 /* FT5416DQ9 touchscreen controller */
352                 .board_info = {
353                         .type = "edt-ft5x06",
354                         .addr = 0x38,
355                         .dev_name = "ft5416",
356                         .swnode = &nextbook_ares8_touchscreen_node,
357                 },
358                 .adapter_path = "\\_SB_.I2C4",
359                 .irq_data = {
360                         .type = X86_ACPI_IRQ_TYPE_GPIOINT,
361                         .chip = "INT33FC:02",
362                         .index = 3,
363                         .trigger = ACPI_EDGE_SENSITIVE,
364                         .polarity = ACPI_ACTIVE_LOW,
365                 },
366         },
367 };
368
369 static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {
370         &int3496_reference_gpios,
371         NULL
372 };
373
374 const struct x86_dev_info nextbook_ares8_info __initconst = {
375         .i2c_client_info = nextbook_ares8_i2c_clients,
376         .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients),
377         .pdev_info = int3496_pdevs,
378         .pdev_count = 1,
379         .gpiod_lookup_tables = nextbook_ares8_gpios,
380         .invalid_aei_gpiochip = "INT33FC:02",
381 };
382
383 /*
384  * Peaq C1010
385  * This is a standard Windows tablet, but it has a special Dolby button.
386  * This button has a WMI interface, but that is broken. Instead of trying to
387  * use the broken WMI interface, instantiate a gpio_keys device for this.
388  */
389 static struct x86_gpio_button peaq_c1010_button = {
390         .button = {
391                 .code = KEY_SOUND,
392                 .active_low = true,
393                 .desc = "dolby_key",
394                 .type = EV_KEY,
395                 .wakeup = false,
396                 .debounce_interval = 50,
397         },
398         .chip = "INT33FC:00",
399         .pin = 3,
400 };
401
402 const struct x86_dev_info peaq_c1010_info __initconst = {
403         .gpio_button = &peaq_c1010_button,
404         /*
405          * Move the ACPI event handler used by the broken WMI interface out of
406          * the way. This is the only event handler on INT33FC:00.
407          */
408         .invalid_aei_gpiochip = "INT33FC:00",
409 };
410
411 /*
412  * Whitelabel (sold as various brands) TM800A550L tablets.
413  * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
414  * (removed through acpi_quirk_skip_i2c_client_enumeration()) and
415  * the touchscreen fwnode has the wrong GPIOs.
416  */
417 static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
418         "-1", "0", "0",
419         "0", "1", "0",
420         "0", "0", "1"
421 };
422
423 static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
424         PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
425         { }
426 };
427
428 static const struct software_node whitelabel_tm800a550l_accel_node = {
429         .properties = whitelabel_tm800a550l_accel_props,
430 };
431
432 static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
433         PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
434         PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
435         PROPERTY_ENTRY_U32("goodix,main-clk", 54),
436         { }
437 };
438
439 static const struct software_node whitelabel_tm800a550l_goodix_node = {
440         .properties = whitelabel_tm800a550l_goodix_props,
441 };
442
443 static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
444         {
445                 /* goodix touchscreen */
446                 .board_info = {
447                         .type = "GDIX1001:00",
448                         .addr = 0x14,
449                         .dev_name = "goodix_ts",
450                         .swnode = &whitelabel_tm800a550l_goodix_node,
451                 },
452                 .adapter_path = "\\_SB_.I2C2",
453                 .irq_data = {
454                         .type = X86_ACPI_IRQ_TYPE_APIC,
455                         .index = 0x44,
456                         .trigger = ACPI_EDGE_SENSITIVE,
457                         .polarity = ACPI_ACTIVE_HIGH,
458                 },
459         }, {
460                 /* kxcj91008 accel */
461                 .board_info = {
462                         .type = "kxcj91008",
463                         .addr = 0x0f,
464                         .dev_name = "kxcj91008",
465                         .swnode = &whitelabel_tm800a550l_accel_node,
466                 },
467                 .adapter_path = "\\_SB_.I2C3",
468         },
469 };
470
471 static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
472         .dev_id = "i2c-goodix_ts",
473         .table = {
474                 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
475                 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
476                 { }
477         },
478 };
479
480 static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
481         &whitelabel_tm800a550l_goodix_gpios,
482         NULL
483 };
484
485 const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
486         .i2c_client_info = whitelabel_tm800a550l_i2c_clients,
487         .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
488         .gpiod_lookup_tables = whitelabel_tm800a550l_gpios,
489 };
490
491 /*
492  * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
493  * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
494  * a bunch of devices to be hidden.
495  *
496  * This takes care of instantiating the hidden devices manually.
497  */
498 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
499         {
500                 /* BQ27520 fuel-gauge */
501                 .board_info = {
502                         .type = "bq27520",
503                         .addr = 0x55,
504                         .dev_name = "bq27520",
505                         .swnode = &fg_bq25890_supply_node,
506                 },
507                 .adapter_path = "\\_SB_.PCI0.I2C1",
508         }, {
509                 /* KTD2026 RGB notification LED controller */
510                 .board_info = {
511                         .type = "ktd2026",
512                         .addr = 0x30,
513                         .dev_name = "ktd2026",
514                 },
515                 .adapter_path = "\\_SB_.PCI0.I2C3",
516         },
517 };
518
519 const struct x86_dev_info xiaomi_mipad2_info __initconst = {
520         .i2c_client_info = xiaomi_mipad2_i2c_clients,
521         .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
522 };
This page took 0.065506 seconds and 4 git commands to generate.