1 // SPDX-License-Identifier: GPL-2.0-or-later
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
11 #include <linux/acpi.h>
12 #include <linux/gpio/machine.h>
13 #include <linux/input.h>
14 #include <linux/leds.h>
15 #include <linux/platform_device.h>
16 #include <linux/pwm.h>
18 #include <dt-bindings/leds/common.h>
20 #include "shared-psy-info.h"
21 #include "x86-android-tablets.h"
23 /* Acer Iconia One 7 B1-750 has an Android factory img with everything hardcoded */
24 static const char * const acer_b1_750_mount_matrix[] = {
30 static const struct property_entry acer_b1_750_bma250e_props[] = {
31 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),
35 static const struct software_node acer_b1_750_bma250e_node = {
36 .properties = acer_b1_750_bma250e_props,
39 static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {
41 /* Novatek NVT-ts touchscreen */
47 .adapter_path = "\\_SB_.I2C4",
49 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
52 .trigger = ACPI_EDGE_SENSITIVE,
53 .polarity = ACPI_ACTIVE_LOW,
54 .con_id = "NVT-ts_irq",
57 /* BMA250E accelerometer */
61 .swnode = &acer_b1_750_bma250e_node,
63 .adapter_path = "\\_SB_.I2C3",
65 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
68 .trigger = ACPI_LEVEL_SENSITIVE,
69 .polarity = ACPI_ACTIVE_HIGH,
70 .con_id = "bma250e_irq",
75 static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {
76 .dev_id = "i2c-NVT-ts",
78 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
83 static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
84 &acer_b1_750_nvt_ts_gpios,
85 &int3496_reference_gpios,
89 const struct x86_dev_info acer_b1_750_info __initconst = {
90 .i2c_client_info = acer_b1_750_i2c_clients,
91 .i2c_client_count = ARRAY_SIZE(acer_b1_750_i2c_clients),
92 .pdev_info = int3496_pdevs,
94 .gpiod_lookup_tables = acer_b1_750_gpios,
99 * This is a standard Windows tablet, but it has an extra "quick launch" button
100 * which is not described in the ACPI tables in anyway.
101 * Use the x86-android-tablets infra to create a gpio-button device for this.
103 static const struct x86_gpio_button advantech_mica_071_button __initconst = {
110 .debounce_interval = 50,
112 .chip = "INT33FC:00",
116 const struct x86_dev_info advantech_mica_071_info __initconst = {
117 .gpio_button = &advantech_mica_071_button,
118 .gpio_button_count = 1,
122 * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT
123 * contains a whole bunch of bogus ACPI I2C devices and is missing entries
124 * for the touchscreen and the accelerometer.
126 static const struct property_entry chuwi_hi8_gsl1680_props[] = {
127 PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
128 PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
129 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
130 PROPERTY_ENTRY_BOOL("silead,home-button"),
131 PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
135 static const struct software_node chuwi_hi8_gsl1680_node = {
136 .properties = chuwi_hi8_gsl1680_props,
139 static const char * const chuwi_hi8_mount_matrix[] = {
145 static const struct property_entry chuwi_hi8_bma250e_props[] = {
146 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
150 static const struct software_node chuwi_hi8_bma250e_node = {
151 .properties = chuwi_hi8_bma250e_props,
154 static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
156 /* Silead touchscreen */
160 .swnode = &chuwi_hi8_gsl1680_node,
162 .adapter_path = "\\_SB_.I2C4",
164 .type = X86_ACPI_IRQ_TYPE_APIC,
166 .trigger = ACPI_EDGE_SENSITIVE,
167 .polarity = ACPI_ACTIVE_HIGH,
170 /* BMA250E accelerometer */
174 .swnode = &chuwi_hi8_bma250e_node,
176 .adapter_path = "\\_SB_.I2C3",
178 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
179 .chip = "INT33FC:02",
181 .trigger = ACPI_LEVEL_SENSITIVE,
182 .polarity = ACPI_ACTIVE_HIGH,
183 .con_id = "bma250e_irq",
188 static int __init chuwi_hi8_init(struct device *dev)
191 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
192 * breaking the touchscreen + logging various errors when the Windows
195 if (acpi_dev_present("MSSL0001", NULL, 1))
201 const struct x86_dev_info chuwi_hi8_info __initconst = {
202 .i2c_client_info = chuwi_hi8_i2c_clients,
203 .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
204 .init = chuwi_hi8_init,
208 * Cyberbook T116 Android version
209 * This comes in both Windows and Android versions and even on Android
210 * the DSDT is mostly sane. This tablet has 2 extra general purpose buttons
211 * in the button row with the power + volume-buttons labeled P and F.
212 * Use the x86-android-tablets infra to create a gpio-button device for these.
214 static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {
222 .debounce_interval = 50,
224 .chip = "INT33FF:00",
234 .debounce_interval = 50,
236 .chip = "INT33FF:03",
241 const struct x86_dev_info cyberbook_t116_info __initconst = {
242 .gpio_button = cyberbook_t116_buttons,
243 .gpio_button_count = ARRAY_SIZE(cyberbook_t116_buttons),
246 #define CZC_EC_EXTRA_PORT 0x68
247 #define CZC_EC_ANDROID_KEYS 0x63
249 static int __init czc_p10t_init(struct device *dev)
252 * The device boots up in "Windows 7" mode, when the home button sends a
253 * Windows specific key sequence (Left Meta + D) and the second button
254 * sends an unknown one while also toggling the Radio Kill Switch.
255 * This is a surprising behavior when the second button is labeled "Back".
257 * The vendor-supplied Android-x86 build switches the device to a "Android"
258 * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
259 * set bit 6 on address 0x96 in the EC region; switching the bit directly
260 * seems to achieve the same result. It uses a "p10t_switcher" to do the
261 * job. It doesn't seem to be able to do anything else, and no other use
262 * of the port 0x68 is known.
264 * In the Android mode, the home button sends just a single scancode,
265 * which can be handled in Linux userspace more reasonably and the back
266 * button only sends a scancode without toggling the kill switch.
267 * The scancode can then be mapped either to Back or RF Kill functionality
268 * in userspace, depending on how the button is labeled on that particular
271 outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
275 const struct x86_dev_info czc_p10t __initconst = {
276 .init = czc_p10t_init,
279 /* Medion Lifetab S10346 tablets have an Android factory img with everything hardcoded */
280 static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
286 static const struct property_entry medion_lifetab_s10346_accel_props[] = {
287 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
291 static const struct software_node medion_lifetab_s10346_accel_node = {
292 .properties = medion_lifetab_s10346_accel_props,
295 /* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
296 static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
297 PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
298 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
302 static const struct software_node medion_lifetab_s10346_touchscreen_node = {
303 .properties = medion_lifetab_s10346_touchscreen_props,
306 static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
308 /* kxtj21009 accel */
312 .dev_name = "kxtj21009",
313 .swnode = &medion_lifetab_s10346_accel_node,
315 .adapter_path = "\\_SB_.I2C3",
317 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
318 .chip = "INT33FC:02",
320 .trigger = ACPI_EDGE_SENSITIVE,
321 .polarity = ACPI_ACTIVE_HIGH,
322 .con_id = "kxtj21009_irq",
325 /* goodix touchscreen */
327 .type = "GDIX1001:00",
329 .dev_name = "goodix_ts",
330 .swnode = &medion_lifetab_s10346_touchscreen_node,
332 .adapter_path = "\\_SB_.I2C4",
334 .type = X86_ACPI_IRQ_TYPE_APIC,
336 .trigger = ACPI_EDGE_SENSITIVE,
337 .polarity = ACPI_ACTIVE_LOW,
342 static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
343 .dev_id = "i2c-goodix_ts",
345 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
346 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
351 static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
352 &medion_lifetab_s10346_goodix_gpios,
356 const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
357 .i2c_client_info = medion_lifetab_s10346_i2c_clients,
358 .i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
359 .gpiod_lookup_tables = medion_lifetab_s10346_gpios,
362 /* Nextbook Ares 8 (BYT) tablets have an Android factory img with everything hardcoded */
363 static const char * const nextbook_ares8_accel_mount_matrix[] = {
369 static const struct property_entry nextbook_ares8_accel_props[] = {
370 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
374 static const struct software_node nextbook_ares8_accel_node = {
375 .properties = nextbook_ares8_accel_props,
378 static const struct property_entry nextbook_ares8_touchscreen_props[] = {
379 PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
380 PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
384 static const struct software_node nextbook_ares8_touchscreen_node = {
385 .properties = nextbook_ares8_touchscreen_props,
388 static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
390 /* Freescale MMA8653FC accel */
394 .dev_name = "mma8653",
395 .swnode = &nextbook_ares8_accel_node,
397 .adapter_path = "\\_SB_.I2C3",
399 /* FT5416DQ9 touchscreen controller */
401 .type = "edt-ft5x06",
403 .dev_name = "ft5416",
404 .swnode = &nextbook_ares8_touchscreen_node,
406 .adapter_path = "\\_SB_.I2C4",
408 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
409 .chip = "INT33FC:02",
411 .trigger = ACPI_EDGE_SENSITIVE,
412 .polarity = ACPI_ACTIVE_LOW,
413 .con_id = "ft5416_irq",
418 static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {
419 &int3496_reference_gpios,
423 const struct x86_dev_info nextbook_ares8_info __initconst = {
424 .i2c_client_info = nextbook_ares8_i2c_clients,
425 .i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients),
426 .pdev_info = int3496_pdevs,
428 .gpiod_lookup_tables = nextbook_ares8_gpios,
431 /* Nextbook Ares 8A (CHT) tablets have an Android factory img with everything hardcoded */
432 static const char * const nextbook_ares8a_accel_mount_matrix[] = {
438 static const struct property_entry nextbook_ares8a_accel_props[] = {
439 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),
443 static const struct software_node nextbook_ares8a_accel_node = {
444 .properties = nextbook_ares8a_accel_props,
447 static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
449 /* Freescale MMA8653FC accel */
453 .dev_name = "mma8653",
454 .swnode = &nextbook_ares8a_accel_node,
456 .adapter_path = "\\_SB_.PCI0.I2C3",
458 /* FT5416DQ9 touchscreen controller */
460 .type = "edt-ft5x06",
462 .dev_name = "ft5416",
463 .swnode = &nextbook_ares8_touchscreen_node,
465 .adapter_path = "\\_SB_.PCI0.I2C6",
467 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
468 .chip = "INT33FF:01",
470 .trigger = ACPI_EDGE_SENSITIVE,
471 .polarity = ACPI_ACTIVE_LOW,
472 .con_id = "ft5416_irq",
477 static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = {
478 .dev_id = "i2c-ft5416",
480 GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW),
485 static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = {
486 &nextbook_ares8a_ft5416_gpios,
490 const struct x86_dev_info nextbook_ares8a_info __initconst = {
491 .i2c_client_info = nextbook_ares8a_i2c_clients,
492 .i2c_client_count = ARRAY_SIZE(nextbook_ares8a_i2c_clients),
493 .gpiod_lookup_tables = nextbook_ares8a_gpios,
498 * This is a standard Windows tablet, but it has a special Dolby button.
499 * This button has a WMI interface, but that is broken. Instead of trying to
500 * use the broken WMI interface, instantiate a gpio_keys device for this.
502 static const struct x86_gpio_button peaq_c1010_button __initconst = {
509 .debounce_interval = 50,
511 .chip = "INT33FC:00",
515 const struct x86_dev_info peaq_c1010_info __initconst = {
516 .gpio_button = &peaq_c1010_button,
517 .gpio_button_count = 1,
521 * Whitelabel (sold as various brands) TM800A550L tablets.
522 * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
523 * (removed through acpi_quirk_skip_i2c_client_enumeration()) and
524 * the touchscreen fwnode has the wrong GPIOs.
526 static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
532 static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
533 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
537 static const struct software_node whitelabel_tm800a550l_accel_node = {
538 .properties = whitelabel_tm800a550l_accel_props,
541 static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
542 PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
543 PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
544 PROPERTY_ENTRY_U32("goodix,main-clk", 54),
548 static const struct software_node whitelabel_tm800a550l_goodix_node = {
549 .properties = whitelabel_tm800a550l_goodix_props,
552 static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
554 /* goodix touchscreen */
556 .type = "GDIX1001:00",
558 .dev_name = "goodix_ts",
559 .swnode = &whitelabel_tm800a550l_goodix_node,
561 .adapter_path = "\\_SB_.I2C2",
563 .type = X86_ACPI_IRQ_TYPE_APIC,
565 .trigger = ACPI_EDGE_SENSITIVE,
566 .polarity = ACPI_ACTIVE_HIGH,
569 /* kxcj91008 accel */
573 .dev_name = "kxcj91008",
574 .swnode = &whitelabel_tm800a550l_accel_node,
576 .adapter_path = "\\_SB_.I2C3",
580 static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
581 .dev_id = "i2c-goodix_ts",
583 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
584 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
589 static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
590 &whitelabel_tm800a550l_goodix_gpios,
594 const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
595 .i2c_client_info = whitelabel_tm800a550l_i2c_clients,
596 .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
597 .gpiod_lookup_tables = whitelabel_tm800a550l_gpios,
601 * The fwnode for ktd2026 on Xaomi pad2. It composed of a RGB LED node
602 * with three subnodes for each color (B/G/R). The RGB LED node is named
603 * "multi-led" to align with the name in the device tree.
606 /* main fwnode for ktd2026 */
607 static const struct software_node ktd2026_node = {
611 static const struct property_entry ktd2026_rgb_led_props[] = {
612 PROPERTY_ENTRY_U32("reg", 0),
613 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB),
614 PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"),
615 PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"),
619 static const struct software_node ktd2026_rgb_led_node = {
621 .properties = ktd2026_rgb_led_props,
622 .parent = &ktd2026_node,
625 static const struct property_entry ktd2026_blue_led_props[] = {
626 PROPERTY_ENTRY_U32("reg", 0),
627 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),
631 static const struct software_node ktd2026_blue_led_node = {
632 .properties = ktd2026_blue_led_props,
633 .parent = &ktd2026_rgb_led_node,
636 static const struct property_entry ktd2026_green_led_props[] = {
637 PROPERTY_ENTRY_U32("reg", 1),
638 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),
642 static const struct software_node ktd2026_green_led_node = {
643 .properties = ktd2026_green_led_props,
644 .parent = &ktd2026_rgb_led_node,
647 static const struct property_entry ktd2026_red_led_props[] = {
648 PROPERTY_ENTRY_U32("reg", 2),
649 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),
653 static const struct software_node ktd2026_red_led_node = {
654 .properties = ktd2026_red_led_props,
655 .parent = &ktd2026_rgb_led_node,
658 static const struct software_node *ktd2026_node_group[] = {
660 &ktd2026_rgb_led_node,
661 &ktd2026_red_led_node,
662 &ktd2026_green_led_node,
663 &ktd2026_blue_led_node,
668 * For the LEDs which backlight the menu / home / back capacitive buttons on
669 * the bottom bezel. These are attached to a TPS61158 LED controller which
670 * is controlled by the "pwm_soc_lpss_2" PWM output.
672 #define XIAOMI_MIPAD2_LED_PERIOD_NS 19200
673 #define XIAOMI_MIPAD2_LED_DEFAULT_DUTY 6000 /* From Android kernel */
675 static struct pwm_device *xiaomi_mipad2_led_pwm;
677 static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
678 enum led_brightness val)
680 struct pwm_state state = {
681 .period = XIAOMI_MIPAD2_LED_PERIOD_NS,
683 /* Always set PWM enabled to avoid the pin floating */
687 return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
690 static int __init xiaomi_mipad2_init(struct device *dev)
692 struct led_classdev *led_cdev;
695 xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2");
696 if (IS_ERR(xiaomi_mipad2_led_pwm))
697 return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n");
699 led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
703 led_cdev->name = "mipad2:white:touch-buttons-backlight";
704 led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS;
705 /* "input-events" trigger uses blink_brightness */
706 led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY;
707 led_cdev->default_trigger = "input-events";
708 led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
710 ret = devm_led_classdev_register(dev, led_cdev);
712 return dev_err_probe(dev, ret, "registering LED\n");
714 return software_node_register_node_group(ktd2026_node_group);
717 static void xiaomi_mipad2_exit(void)
719 software_node_unregister_node_group(ktd2026_node_group);
723 * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
724 * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
725 * a bunch of devices to be hidden.
727 * This takes care of instantiating the hidden devices manually.
729 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
731 /* BQ27520 fuel-gauge */
735 .dev_name = "bq27520",
736 .swnode = &fg_bq25890_supply_node,
738 .adapter_path = "\\_SB_.PCI0.I2C1",
740 /* KTD2026 RGB notification LED controller */
744 .dev_name = "ktd2026",
745 .swnode = &ktd2026_node,
747 .adapter_path = "\\_SB_.PCI0.I2C3",
751 const struct x86_dev_info xiaomi_mipad2_info __initconst = {
752 .i2c_client_info = xiaomi_mipad2_i2c_clients,
753 .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
754 .init = xiaomi_mipad2_init,
755 .exit = xiaomi_mipad2_exit,