Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / platform / x86 / x86-android-tablets / other.c
blob735df818f76bfe97099f5952d08b8d4b35613b55
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.
8 * Copyright (C) 2021-2023 Hans de Goede <hdegoede@redhat.com>
9 */
11 #include <linux/acpi.h>
12 #include <linux/gpio/machine.h>
13 #include <linux/input.h>
14 #include <linux/leds.h>
15 #include <linux/pci.h>
16 #include <linux/platform_device.h>
17 #include <linux/pwm.h>
19 #include <dt-bindings/leds/common.h>
21 #include "shared-psy-info.h"
22 #include "x86-android-tablets.h"
24 /* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */
25 static const char * const acer_b1_750_mount_matrix[] = {
26 "-1", "0", "0",
27 "0", "1", "0",
28 "0", "0", "1"
31 static const struct property_entry acer_b1_750_bma250e_props[] = {
32 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),
33 { }
36 static const struct software_node acer_b1_750_bma250e_node = {
37 .properties = acer_b1_750_bma250e_props,
40 static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {
42 /* Novatek NVT-ts touchscreen */
43 .board_info = {
44 .type = "nt11205-ts",
45 .addr = 0x34,
46 .dev_name = "NVT-ts",
48 .adapter_path = "\\_SB_.I2C4",
49 .irq_data = {
50 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
51 .chip = "INT33FC:02",
52 .index = 3,
53 .trigger = ACPI_EDGE_SENSITIVE,
54 .polarity = ACPI_ACTIVE_LOW,
55 .con_id = "NVT-ts_irq",
57 }, {
58 /* BMA250E accelerometer */
59 .board_info = {
60 .type = "bma250e",
61 .addr = 0x18,
62 .swnode = &acer_b1_750_bma250e_node,
64 .adapter_path = "\\_SB_.I2C3",
65 .irq_data = {
66 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
67 .chip = "INT33FC:02",
68 .index = 25,
69 .trigger = ACPI_LEVEL_SENSITIVE,
70 .polarity = ACPI_ACTIVE_HIGH,
71 .con_id = "bma250e_irq",
76 static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {
77 .dev_id = "i2c-NVT-ts",
78 .table = {
79 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
80 { }
84 static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
85 &acer_b1_750_nvt_ts_gpios,
86 &int3496_reference_gpios,
87 NULL
90 const struct x86_dev_info acer_b1_750_info __initconst = {
91 .i2c_client_info = acer_b1_750_i2c_clients,
92 .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients),
93 .pdev_info = int3496_pdevs,
94 .pdev_count = 1,
95 .gpiod_lookup_tables = acer_b1_750_gpios,
99 * Advantech MICA-071
100 * This is a standard Windows tablet, but it has an extra "quick launch" button
101 * which is not described in the ACPI tables in anyway.
102 * Use the x86-android-tablets infra to create a gpio-keys device for this.
104 static const struct x86_gpio_button advantech_mica_071_button __initconst = {
105 .button = {
106 .code = KEY_PROG1,
107 .active_low = true,
108 .desc = "prog1_key",
109 .type = EV_KEY,
110 .wakeup = false,
111 .debounce_interval = 50,
113 .chip = "INT33FC:00",
114 .pin = 2,
117 const struct x86_dev_info advantech_mica_071_info __initconst = {
118 .gpio_button = &advantech_mica_071_button,
119 .gpio_button_count = 1,
123 * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT
124 * contains a whole bunch of bogus ACPI I2C devices and is missing entries
125 * for the touchscreen and the accelerometer.
127 static const struct property_entry chuwi_hi8_gsl1680_props[] = {
128 PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
129 PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
130 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
131 PROPERTY_ENTRY_BOOL("silead,home-button"),
132 PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
136 static const struct software_node chuwi_hi8_gsl1680_node = {
137 .properties = chuwi_hi8_gsl1680_props,
140 static const char * const chuwi_hi8_mount_matrix[] = {
141 "1", "0", "0",
142 "0", "-1", "0",
143 "0", "0", "1"
146 static const struct property_entry chuwi_hi8_bma250e_props[] = {
147 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
151 static const struct software_node chuwi_hi8_bma250e_node = {
152 .properties = chuwi_hi8_bma250e_props,
155 static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
157 /* Silead touchscreen */
158 .board_info = {
159 .type = "gsl1680",
160 .addr = 0x40,
161 .swnode = &chuwi_hi8_gsl1680_node,
163 .adapter_path = "\\_SB_.I2C4",
164 .irq_data = {
165 .type = X86_ACPI_IRQ_TYPE_APIC,
166 .index = 0x44,
167 .trigger = ACPI_EDGE_SENSITIVE,
168 .polarity = ACPI_ACTIVE_HIGH,
170 }, {
171 /* BMA250E accelerometer */
172 .board_info = {
173 .type = "bma250e",
174 .addr = 0x18,
175 .swnode = &chuwi_hi8_bma250e_node,
177 .adapter_path = "\\_SB_.I2C3",
178 .irq_data = {
179 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
180 .chip = "INT33FC:02",
181 .index = 23,
182 .trigger = ACPI_LEVEL_SENSITIVE,
183 .polarity = ACPI_ACTIVE_HIGH,
184 .con_id = "bma250e_irq",
189 static int __init chuwi_hi8_init(struct device *dev)
192 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
193 * breaking the touchscreen + logging various errors when the Windows
194 * BIOS is used.
196 if (acpi_dev_present("MSSL0001", NULL, 1))
197 return -ENODEV;
199 return 0;
202 const struct x86_dev_info chuwi_hi8_info __initconst = {
203 .i2c_client_info = chuwi_hi8_i2c_clients,
204 .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
205 .init = chuwi_hi8_init,
209 * Cyberbook T116 Android version
210 * This comes in both Windows and Android versions and even on Android
211 * the DSDT is mostly sane. This tablet has 2 extra general purpose buttons
212 * in the button row with the power + volume-buttons labeled P and F.
213 * Use the x86-android-tablets infra to create a gpio-keys device for these.
215 static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {
217 .button = {
218 .code = KEY_PROG1,
219 .active_low = true,
220 .desc = "prog1_key",
221 .type = EV_KEY,
222 .wakeup = false,
223 .debounce_interval = 50,
225 .chip = "INT33FF:00",
226 .pin = 30,
229 .button = {
230 .code = KEY_PROG2,
231 .active_low = true,
232 .desc = "prog2_key",
233 .type = EV_KEY,
234 .wakeup = false,
235 .debounce_interval = 50,
237 .chip = "INT33FF:03",
238 .pin = 48,
242 const struct x86_dev_info cyberbook_t116_info __initconst = {
243 .gpio_button = cyberbook_t116_buttons,
244 .gpio_button_count = ARRAY_SIZE(cyberbook_t116_buttons),
247 #define CZC_EC_EXTRA_PORT 0x68
248 #define CZC_EC_ANDROID_KEYS 0x63
250 static int __init czc_p10t_init(struct device *dev)
253 * The device boots up in "Windows 7" mode, when the home button sends a
254 * Windows specific key sequence (Left Meta + D) and the second button
255 * sends an unknown one while also toggling the Radio Kill Switch.
256 * This is a surprising behavior when the second button is labeled "Back".
258 * The vendor-supplied Android-x86 build switches the device to a "Android"
259 * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
260 * set bit 6 on address 0x96 in the EC region; switching the bit directly
261 * seems to achieve the same result. It uses a "p10t_switcher" to do the
262 * job. It doesn't seem to be able to do anything else, and no other use
263 * of the port 0x68 is known.
265 * In the Android mode, the home button sends just a single scancode,
266 * which can be handled in Linux userspace more reasonably and the back
267 * button only sends a scancode without toggling the kill switch.
268 * The scancode can then be mapped either to Back or RF Kill functionality
269 * in userspace, depending on how the button is labeled on that particular
270 * model.
272 outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
273 return 0;
276 const struct x86_dev_info czc_p10t __initconst = {
277 .init = czc_p10t_init,
280 /* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */
281 static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
282 "0", "1", "0",
283 "1", "0", "0",
284 "0", "0", "1"
287 static const struct property_entry medion_lifetab_s10346_accel_props[] = {
288 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
292 static const struct software_node medion_lifetab_s10346_accel_node = {
293 .properties = medion_lifetab_s10346_accel_props,
296 /* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
297 static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
298 PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
299 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
303 static const struct software_node medion_lifetab_s10346_touchscreen_node = {
304 .properties = medion_lifetab_s10346_touchscreen_props,
307 static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
309 /* kxtj21009 accelerometer */
310 .board_info = {
311 .type = "kxtj21009",
312 .addr = 0x0f,
313 .dev_name = "kxtj21009",
314 .swnode = &medion_lifetab_s10346_accel_node,
316 .adapter_path = "\\_SB_.I2C3",
317 .irq_data = {
318 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
319 .chip = "INT33FC:02",
320 .index = 23,
321 .trigger = ACPI_EDGE_SENSITIVE,
322 .polarity = ACPI_ACTIVE_HIGH,
323 .con_id = "kxtj21009_irq",
325 }, {
326 /* goodix touchscreen */
327 .board_info = {
328 .type = "GDIX1001:00",
329 .addr = 0x14,
330 .dev_name = "goodix_ts",
331 .swnode = &medion_lifetab_s10346_touchscreen_node,
333 .adapter_path = "\\_SB_.I2C4",
334 .irq_data = {
335 .type = X86_ACPI_IRQ_TYPE_APIC,
336 .index = 0x44,
337 .trigger = ACPI_EDGE_SENSITIVE,
338 .polarity = ACPI_ACTIVE_LOW,
343 static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
344 .dev_id = "i2c-goodix_ts",
345 .table = {
346 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
347 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
352 static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
353 &medion_lifetab_s10346_goodix_gpios,
354 NULL
357 const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
358 .i2c_client_info = medion_lifetab_s10346_i2c_clients,
359 .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
360 .gpiod_lookup_tables = medion_lifetab_s10346_gpios,
363 /* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
364 static const char * const nextbook_ares8_accel_mount_matrix[] = {
365 "0", "-1", "0",
366 "-1", "0", "0",
367 "0", "0", "1"
370 static const struct property_entry nextbook_ares8_accel_props[] = {
371 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
375 static const struct software_node nextbook_ares8_accel_node = {
376 .properties = nextbook_ares8_accel_props,
379 static const struct property_entry nextbook_ares8_touchscreen_props[] = {
380 PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
381 PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
385 static const struct software_node nextbook_ares8_touchscreen_node = {
386 .properties = nextbook_ares8_touchscreen_props,
389 static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
391 /* Freescale MMA8653FC accelerometer */
392 .board_info = {
393 .type = "mma8653",
394 .addr = 0x1d,
395 .dev_name = "mma8653",
396 .swnode = &nextbook_ares8_accel_node,
398 .adapter_path = "\\_SB_.I2C3",
399 }, {
400 /* FT5416DQ9 touchscreen controller */
401 .board_info = {
402 .type = "edt-ft5x06",
403 .addr = 0x38,
404 .dev_name = "ft5416",
405 .swnode = &nextbook_ares8_touchscreen_node,
407 .adapter_path = "\\_SB_.I2C4",
408 .irq_data = {
409 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
410 .chip = "INT33FC:02",
411 .index = 3,
412 .trigger = ACPI_EDGE_SENSITIVE,
413 .polarity = ACPI_ACTIVE_LOW,
414 .con_id = "ft5416_irq",
419 static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {
420 &int3496_reference_gpios,
421 NULL
424 const struct x86_dev_info nextbook_ares8_info __initconst = {
425 .i2c_client_info = nextbook_ares8_i2c_clients,
426 .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients),
427 .pdev_info = int3496_pdevs,
428 .pdev_count = 1,
429 .gpiod_lookup_tables = nextbook_ares8_gpios,
432 /* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */
433 static const char * const nextbook_ares8a_accel_mount_matrix[] = {
434 "1", "0", "0",
435 "0", "-1", "0",
436 "0", "0", "1"
439 static const struct property_entry nextbook_ares8a_accel_props[] = {
440 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),
444 static const struct software_node nextbook_ares8a_accel_node = {
445 .properties = nextbook_ares8a_accel_props,
448 static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
450 /* Freescale MMA8653FC accelerometer */
451 .board_info = {
452 .type = "mma8653",
453 .addr = 0x1d,
454 .dev_name = "mma8653",
455 .swnode = &nextbook_ares8a_accel_node,
457 .adapter_path = "\\_SB_.PCI0.I2C3",
458 }, {
459 /* FT5416DQ9 touchscreen controller */
460 .board_info = {
461 .type = "edt-ft5x06",
462 .addr = 0x38,
463 .dev_name = "ft5416",
464 .swnode = &nextbook_ares8_touchscreen_node,
466 .adapter_path = "\\_SB_.PCI0.I2C6",
467 .irq_data = {
468 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
469 .chip = "INT33FF:01",
470 .index = 17,
471 .trigger = ACPI_EDGE_SENSITIVE,
472 .polarity = ACPI_ACTIVE_LOW,
473 .con_id = "ft5416_irq",
478 static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = {
479 .dev_id = "i2c-ft5416",
480 .table = {
481 GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW),
486 static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = {
487 &nextbook_ares8a_ft5416_gpios,
488 NULL
491 const struct x86_dev_info nextbook_ares8a_info __initconst = {
492 .i2c_client_info = nextbook_ares8a_i2c_clients,
493 .i2c_client_count = ARRAY_SIZE(nextbook_ares8a_i2c_clients),
494 .gpiod_lookup_tables = nextbook_ares8a_gpios,
498 * Peaq C1010
499 * This is a standard Windows tablet, but it has a special Dolby button.
500 * This button has a WMI interface, but that is broken. Instead of trying to
501 * use the broken WMI interface, instantiate a gpio-keys device for this.
503 static const struct x86_gpio_button peaq_c1010_button __initconst = {
504 .button = {
505 .code = KEY_SOUND,
506 .active_low = true,
507 .desc = "dolby_key",
508 .type = EV_KEY,
509 .wakeup = false,
510 .debounce_interval = 50,
512 .chip = "INT33FC:00",
513 .pin = 3,
516 const struct x86_dev_info peaq_c1010_info __initconst = {
517 .gpio_button = &peaq_c1010_button,
518 .gpio_button_count = 1,
522 * Whitelabel (sold as various brands) TM800A550L tablets.
523 * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
524 * (removed through acpi_quirk_skip_i2c_client_enumeration()) and
525 * the touchscreen firmware node has the wrong GPIOs.
527 static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
528 "-1", "0", "0",
529 "0", "1", "0",
530 "0", "0", "1"
533 static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
534 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
538 static const struct software_node whitelabel_tm800a550l_accel_node = {
539 .properties = whitelabel_tm800a550l_accel_props,
542 static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
543 PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
544 PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
545 PROPERTY_ENTRY_U32("goodix,main-clk", 54),
549 static const struct software_node whitelabel_tm800a550l_goodix_node = {
550 .properties = whitelabel_tm800a550l_goodix_props,
553 static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
555 /* goodix touchscreen */
556 .board_info = {
557 .type = "GDIX1001:00",
558 .addr = 0x14,
559 .dev_name = "goodix_ts",
560 .swnode = &whitelabel_tm800a550l_goodix_node,
562 .adapter_path = "\\_SB_.I2C2",
563 .irq_data = {
564 .type = X86_ACPI_IRQ_TYPE_APIC,
565 .index = 0x44,
566 .trigger = ACPI_EDGE_SENSITIVE,
567 .polarity = ACPI_ACTIVE_HIGH,
569 }, {
570 /* kxcj91008 accelerometer */
571 .board_info = {
572 .type = "kxcj91008",
573 .addr = 0x0f,
574 .dev_name = "kxcj91008",
575 .swnode = &whitelabel_tm800a550l_accel_node,
577 .adapter_path = "\\_SB_.I2C3",
581 static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
582 .dev_id = "i2c-goodix_ts",
583 .table = {
584 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
585 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
590 static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
591 &whitelabel_tm800a550l_goodix_gpios,
592 NULL
595 const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
596 .i2c_client_info = whitelabel_tm800a550l_i2c_clients,
597 .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
598 .gpiod_lookup_tables = whitelabel_tm800a550l_gpios,
602 * Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet
603 * distributed to schools in the Spanish Andalucía region.
605 const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
607 static const struct property_entry vexia_edu_atla10_ulpmc_props[] = {
608 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
612 const struct software_node vexia_edu_atla10_ulpmc_node = {
613 .properties = vexia_edu_atla10_ulpmc_props,
616 static const char * const vexia_edu_atla10_accel_mount_matrix[] = {
617 "0", "-1", "0",
618 "1", "0", "0",
619 "0", "0", "1"
622 static const struct property_entry vexia_edu_atla10_accel_props[] = {
623 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix),
627 static const struct software_node vexia_edu_atla10_accel_node = {
628 .properties = vexia_edu_atla10_accel_props,
631 static const struct property_entry vexia_edu_atla10_touchscreen_props[] = {
632 PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
633 PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
637 static const struct software_node vexia_edu_atla10_touchscreen_node = {
638 .properties = vexia_edu_atla10_touchscreen_props,
641 static const struct property_entry vexia_edu_atla10_pmic_props[] = {
642 PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
646 static const struct software_node vexia_edu_atla10_pmic_node = {
647 .properties = vexia_edu_atla10_pmic_props,
650 static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = {
652 /* I2C attached embedded controller, used to access fuel-gauge */
653 .board_info = {
654 .type = "vexia_atla10_ec",
655 .addr = 0x76,
656 .dev_name = "ulpmc",
657 .swnode = &vexia_edu_atla10_ulpmc_node,
659 .adapter_path = "0000:00:18.1",
660 }, {
661 /* RT5642 audio codec */
662 .board_info = {
663 .type = "rt5640",
664 .addr = 0x1c,
665 .dev_name = "rt5640",
667 .adapter_path = "0000:00:18.2",
668 .irq_data = {
669 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
670 .chip = "INT33FC:02",
671 .index = 4,
672 .trigger = ACPI_EDGE_SENSITIVE,
673 .polarity = ACPI_ACTIVE_HIGH,
674 .con_id = "rt5640_irq",
676 }, {
677 /* kxtj21009 accelerometer */
678 .board_info = {
679 .type = "kxtj21009",
680 .addr = 0x0f,
681 .dev_name = "kxtj21009",
682 .swnode = &vexia_edu_atla10_accel_node,
684 .adapter_path = "0000:00:18.5",
685 }, {
686 /* FT5416DQ9 touchscreen controller */
687 .board_info = {
688 .type = "hid-over-i2c",
689 .addr = 0x38,
690 .dev_name = "FTSC1000",
691 .swnode = &vexia_edu_atla10_touchscreen_node,
693 .adapter_path = "0000:00:18.6",
694 .irq_data = {
695 .type = X86_ACPI_IRQ_TYPE_APIC,
696 .index = 0x45,
697 .trigger = ACPI_LEVEL_SENSITIVE,
698 .polarity = ACPI_ACTIVE_HIGH,
700 }, {
701 /* Crystal Cove PMIC */
702 .board_info = {
703 .type = "intel_soc_pmic_crc",
704 .addr = 0x6e,
705 .dev_name = "intel_soc_pmic_crc",
706 .swnode = &vexia_edu_atla10_pmic_node,
708 .adapter_path = "0000:00:18.7",
709 .irq_data = {
710 .type = X86_ACPI_IRQ_TYPE_APIC,
711 .index = 0x43,
712 .trigger = ACPI_LEVEL_SENSITIVE,
713 .polarity = ACPI_ACTIVE_HIGH,
718 static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = {
719 .dev_id = "i2c-FTSC1000",
720 .table = {
721 GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW),
726 static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = {
727 &vexia_edu_atla10_ft5416_gpios,
728 NULL
731 static int __init vexia_edu_atla10_init(struct device *dev)
733 struct pci_dev *pdev;
734 int ret;
736 /* Enable the Wifi module by setting the wifi_enable pin to 1 */
737 ret = x86_android_tablet_get_gpiod("INT33FC:02", 20, "wifi_enable",
738 false, GPIOD_OUT_HIGH, NULL);
739 if (ret)
740 return ret;
742 /* Reprobe the SDIO controller to enumerate the now enabled Wifi module */
743 pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x11, 0));
744 if (!pdev)
745 return -EPROBE_DEFER;
747 ret = device_reprobe(&pdev->dev);
748 if (ret)
749 pci_warn(pdev, "Reprobing error: %d\n", ret);
751 pci_dev_put(pdev);
752 return 0;
755 const struct x86_dev_info vexia_edu_atla10_info __initconst = {
756 .i2c_client_info = vexia_edu_atla10_i2c_clients,
757 .i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_i2c_clients),
758 .gpiod_lookup_tables = vexia_edu_atla10_gpios,
759 .init = vexia_edu_atla10_init,
760 .use_pci_devname = true,
764 * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node
765 * with three subnodes for each color (B/G/R). The RGB LED node is named
766 * "multi-led" to align with the name in the device tree.
769 /* Main firmware node for ktd2026 */
770 static const struct software_node ktd2026_node = {
771 .name = "ktd2026",
774 static const struct property_entry ktd2026_rgb_led_props[] = {
775 PROPERTY_ENTRY_U32("reg", 0),
776 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB),
777 PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"),
778 PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"),
782 static const struct software_node ktd2026_rgb_led_node = {
783 .name = "multi-led",
784 .properties = ktd2026_rgb_led_props,
785 .parent = &ktd2026_node,
788 static const struct property_entry ktd2026_blue_led_props[] = {
789 PROPERTY_ENTRY_U32("reg", 0),
790 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),
794 static const struct software_node ktd2026_blue_led_node = {
795 .properties = ktd2026_blue_led_props,
796 .parent = &ktd2026_rgb_led_node,
799 static const struct property_entry ktd2026_green_led_props[] = {
800 PROPERTY_ENTRY_U32("reg", 1),
801 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),
805 static const struct software_node ktd2026_green_led_node = {
806 .properties = ktd2026_green_led_props,
807 .parent = &ktd2026_rgb_led_node,
810 static const struct property_entry ktd2026_red_led_props[] = {
811 PROPERTY_ENTRY_U32("reg", 2),
812 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),
816 static const struct software_node ktd2026_red_led_node = {
817 .properties = ktd2026_red_led_props,
818 .parent = &ktd2026_rgb_led_node,
821 static const struct software_node *ktd2026_node_group[] = {
822 &ktd2026_node,
823 &ktd2026_rgb_led_node,
824 &ktd2026_red_led_node,
825 &ktd2026_green_led_node,
826 &ktd2026_blue_led_node,
827 NULL
831 * For the LEDs which backlight the Menu / Home / Back capacitive buttons on
832 * the bottom bezel. These are attached to a TPS61158 LED controller which
833 * is controlled by the "pwm_soc_lpss_2" PWM output.
835 #define XIAOMI_MIPAD2_LED_PERIOD_NS 19200
836 #define XIAOMI_MIPAD2_LED_MAX_DUTY_NS 6000 /* From Android kernel */
838 static struct pwm_device *xiaomi_mipad2_led_pwm;
840 static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
841 enum led_brightness val)
843 struct pwm_state state = {
844 .period = XIAOMI_MIPAD2_LED_PERIOD_NS,
845 .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
846 /* Always set PWM enabled to avoid the pin floating */
847 .enabled = true,
850 return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
853 static int __init xiaomi_mipad2_init(struct device *dev)
855 struct led_classdev *led_cdev;
856 int ret;
858 xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2");
859 if (IS_ERR(xiaomi_mipad2_led_pwm))
860 return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n");
862 led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
863 if (!led_cdev)
864 return -ENOMEM;
866 led_cdev->name = "mipad2:white:touch-buttons-backlight";
867 led_cdev->max_brightness = LED_FULL;
868 led_cdev->default_trigger = "input-events";
869 led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
870 /* Turn LED off during suspend */
871 led_cdev->flags = LED_CORE_SUSPENDRESUME;
873 ret = devm_led_classdev_register(dev, led_cdev);
874 if (ret)
875 return dev_err_probe(dev, ret, "registering LED\n");
877 return software_node_register_node_group(ktd2026_node_group);
880 static void xiaomi_mipad2_exit(void)
882 software_node_unregister_node_group(ktd2026_node_group);
886 * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
887 * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
888 * a bunch of devices to be hidden.
890 * This takes care of instantiating the hidden devices manually.
892 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
894 /* BQ27520 fuel-gauge */
895 .board_info = {
896 .type = "bq27520",
897 .addr = 0x55,
898 .dev_name = "bq27520",
899 .swnode = &fg_bq25890_supply_node,
901 .adapter_path = "\\_SB_.PCI0.I2C1",
902 }, {
903 /* KTD2026 RGB notification LED controller */
904 .board_info = {
905 .type = "ktd2026",
906 .addr = 0x30,
907 .dev_name = "ktd2026",
908 .swnode = &ktd2026_node,
910 .adapter_path = "\\_SB_.PCI0.I2C3",
914 const struct x86_dev_info xiaomi_mipad2_info __initconst = {
915 .i2c_client_info = xiaomi_mipad2_i2c_clients,
916 .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
917 .init = xiaomi_mipad2_init,
918 .exit = xiaomi_mipad2_exit,