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
8 * Copyright (C) 2021-2023 Hans de Goede <hdegoede@redhat.com>
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
[] = {
31 static const struct property_entry acer_b1_750_bma250e_props
[] = {
32 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix
),
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 */
48 .adapter_path
= "\\_SB_.I2C4",
50 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
53 .trigger
= ACPI_EDGE_SENSITIVE
,
54 .polarity
= ACPI_ACTIVE_LOW
,
55 .con_id
= "NVT-ts_irq",
58 /* BMA250E accelerometer */
62 .swnode
= &acer_b1_750_bma250e_node
,
64 .adapter_path
= "\\_SB_.I2C3",
66 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
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",
79 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW
),
84 static struct gpiod_lookup_table
* const acer_b1_750_gpios
[] = {
85 &acer_b1_750_nvt_ts_gpios
,
86 &int3496_reference_gpios
,
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
,
95 .gpiod_lookup_tables
= acer_b1_750_gpios
,
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
= {
111 .debounce_interval
= 50,
113 .chip
= "INT33FC:00",
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
[] = {
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 */
161 .swnode
= &chuwi_hi8_gsl1680_node
,
163 .adapter_path
= "\\_SB_.I2C4",
165 .type
= X86_ACPI_IRQ_TYPE_APIC
,
167 .trigger
= ACPI_EDGE_SENSITIVE
,
168 .polarity
= ACPI_ACTIVE_HIGH
,
171 /* BMA250E accelerometer */
175 .swnode
= &chuwi_hi8_bma250e_node
,
177 .adapter_path
= "\\_SB_.I2C3",
179 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
180 .chip
= "INT33FC:02",
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
196 if (acpi_dev_present("MSSL0001", NULL
, 1))
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
= {
223 .debounce_interval
= 50,
225 .chip
= "INT33FF:00",
235 .debounce_interval
= 50,
237 .chip
= "INT33FF:03",
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
272 outb(CZC_EC_ANDROID_KEYS
, CZC_EC_EXTRA_PORT
);
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
[] = {
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 */
313 .dev_name
= "kxtj21009",
314 .swnode
= &medion_lifetab_s10346_accel_node
,
316 .adapter_path
= "\\_SB_.I2C3",
318 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
319 .chip
= "INT33FC:02",
321 .trigger
= ACPI_EDGE_SENSITIVE
,
322 .polarity
= ACPI_ACTIVE_HIGH
,
323 .con_id
= "kxtj21009_irq",
326 /* goodix touchscreen */
328 .type
= "GDIX1001:00",
330 .dev_name
= "goodix_ts",
331 .swnode
= &medion_lifetab_s10346_touchscreen_node
,
333 .adapter_path
= "\\_SB_.I2C4",
335 .type
= X86_ACPI_IRQ_TYPE_APIC
,
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",
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
,
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
[] = {
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 */
395 .dev_name
= "mma8653",
396 .swnode
= &nextbook_ares8_accel_node
,
398 .adapter_path
= "\\_SB_.I2C3",
400 /* FT5416DQ9 touchscreen controller */
402 .type
= "edt-ft5x06",
404 .dev_name
= "ft5416",
405 .swnode
= &nextbook_ares8_touchscreen_node
,
407 .adapter_path
= "\\_SB_.I2C4",
409 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
410 .chip
= "INT33FC:02",
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
,
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
,
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
[] = {
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 */
454 .dev_name
= "mma8653",
455 .swnode
= &nextbook_ares8a_accel_node
,
457 .adapter_path
= "\\_SB_.PCI0.I2C3",
459 /* FT5416DQ9 touchscreen controller */
461 .type
= "edt-ft5x06",
463 .dev_name
= "ft5416",
464 .swnode
= &nextbook_ares8_touchscreen_node
,
466 .adapter_path
= "\\_SB_.PCI0.I2C6",
468 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
469 .chip
= "INT33FF:01",
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",
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
,
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
,
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
= {
510 .debounce_interval
= 50,
512 .chip
= "INT33FC:00",
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
[] = {
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 */
557 .type
= "GDIX1001:00",
559 .dev_name
= "goodix_ts",
560 .swnode
= &whitelabel_tm800a550l_goodix_node
,
562 .adapter_path
= "\\_SB_.I2C2",
564 .type
= X86_ACPI_IRQ_TYPE_APIC
,
566 .trigger
= ACPI_EDGE_SENSITIVE
,
567 .polarity
= ACPI_ACTIVE_HIGH
,
570 /* kxcj91008 accelerometer */
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",
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
,
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
[] = {
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 */
654 .type
= "vexia_atla10_ec",
657 .swnode
= &vexia_edu_atla10_ulpmc_node
,
659 .adapter_path
= "0000:00:18.1",
661 /* RT5642 audio codec */
665 .dev_name
= "rt5640",
667 .adapter_path
= "0000:00:18.2",
669 .type
= X86_ACPI_IRQ_TYPE_GPIOINT
,
670 .chip
= "INT33FC:02",
672 .trigger
= ACPI_EDGE_SENSITIVE
,
673 .polarity
= ACPI_ACTIVE_HIGH
,
674 .con_id
= "rt5640_irq",
677 /* kxtj21009 accelerometer */
681 .dev_name
= "kxtj21009",
682 .swnode
= &vexia_edu_atla10_accel_node
,
684 .adapter_path
= "0000:00:18.5",
686 /* FT5416DQ9 touchscreen controller */
688 .type
= "hid-over-i2c",
690 .dev_name
= "FTSC1000",
691 .swnode
= &vexia_edu_atla10_touchscreen_node
,
693 .adapter_path
= "0000:00:18.6",
695 .type
= X86_ACPI_IRQ_TYPE_APIC
,
697 .trigger
= ACPI_LEVEL_SENSITIVE
,
698 .polarity
= ACPI_ACTIVE_HIGH
,
701 /* Crystal Cove PMIC */
703 .type
= "intel_soc_pmic_crc",
705 .dev_name
= "intel_soc_pmic_crc",
706 .swnode
= &vexia_edu_atla10_pmic_node
,
708 .adapter_path
= "0000:00:18.7",
710 .type
= X86_ACPI_IRQ_TYPE_APIC
,
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",
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
,
731 static int __init
vexia_edu_atla10_init(struct device
*dev
)
733 struct pci_dev
*pdev
;
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
);
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));
745 return -EPROBE_DEFER
;
747 ret
= device_reprobe(&pdev
->dev
);
749 pci_warn(pdev
, "Reprobing error: %d\n", ret
);
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
= {
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
= {
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
[] = {
823 &ktd2026_rgb_led_node
,
824 &ktd2026_red_led_node
,
825 &ktd2026_green_led_node
,
826 &ktd2026_blue_led_node
,
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 */
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
;
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
);
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
);
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 */
898 .dev_name
= "bq27520",
899 .swnode
= &fg_bq25890_supply_node
,
901 .adapter_path
= "\\_SB_.PCI0.I2C1",
903 /* KTD2026 RGB notification LED controller */
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
,