757 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * DMI based code to deal with broken DSDTs on X86 tablets which ship with4 * Android as (part of) the factory image. The factory kernels shipped on these5 * devices typically have a bunch of things hardcoded, rather than specified6 * in their DSDT.7 *8 * Copyright (C) 2021-2023 Hans de Goede <hdegoede@redhat.com>9 */10 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>17 18#include <dt-bindings/leds/common.h>19 20#include "shared-psy-info.h"21#include "x86-android-tablets.h"22 23/* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */24static const char * const acer_b1_750_mount_matrix[] = {25 "-1", "0", "0",26 "0", "1", "0",27 "0", "0", "1"28};29 30static const struct property_entry acer_b1_750_bma250e_props[] = {31 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),32 { }33};34 35static const struct software_node acer_b1_750_bma250e_node = {36 .properties = acer_b1_750_bma250e_props,37};38 39static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {40 {41 /* Novatek NVT-ts touchscreen */42 .board_info = {43 .type = "NVT-ts",44 .addr = 0x34,45 .dev_name = "NVT-ts",46 },47 .adapter_path = "\\_SB_.I2C4",48 .irq_data = {49 .type = X86_ACPI_IRQ_TYPE_GPIOINT,50 .chip = "INT33FC:02",51 .index = 3,52 .trigger = ACPI_EDGE_SENSITIVE,53 .polarity = ACPI_ACTIVE_LOW,54 .con_id = "NVT-ts_irq",55 },56 }, {57 /* BMA250E accelerometer */58 .board_info = {59 .type = "bma250e",60 .addr = 0x18,61 .swnode = &acer_b1_750_bma250e_node,62 },63 .adapter_path = "\\_SB_.I2C3",64 .irq_data = {65 .type = X86_ACPI_IRQ_TYPE_GPIOINT,66 .chip = "INT33FC:02",67 .index = 25,68 .trigger = ACPI_LEVEL_SENSITIVE,69 .polarity = ACPI_ACTIVE_HIGH,70 .con_id = "bma250e_irq",71 },72 },73};74 75static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {76 .dev_id = "i2c-NVT-ts",77 .table = {78 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),79 { }80 },81};82 83static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {84 &acer_b1_750_nvt_ts_gpios,85 &int3496_reference_gpios,86 NULL87};88 89const 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,93 .pdev_count = 1,94 .gpiod_lookup_tables = acer_b1_750_gpios,95};96 97/*98 * Advantech MICA-07199 * This is a standard Windows tablet, but it has an extra "quick launch" button100 * which is not described in the ACPI tables in anyway.101 * Use the x86-android-tablets infra to create a gpio-keys device for this.102 */103static const struct x86_gpio_button advantech_mica_071_button __initconst = {104 .button = {105 .code = KEY_PROG1,106 .active_low = true,107 .desc = "prog1_key",108 .type = EV_KEY,109 .wakeup = false,110 .debounce_interval = 50,111 },112 .chip = "INT33FC:00",113 .pin = 2,114};115 116const struct x86_dev_info advantech_mica_071_info __initconst = {117 .gpio_button = &advantech_mica_071_button,118 .gpio_button_count = 1,119};120 121/*122 * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT123 * contains a whole bunch of bogus ACPI I2C devices and is missing entries124 * for the touchscreen and the accelerometer.125 */126static 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"),132 { }133};134 135static const struct software_node chuwi_hi8_gsl1680_node = {136 .properties = chuwi_hi8_gsl1680_props,137};138 139static const char * const chuwi_hi8_mount_matrix[] = {140 "1", "0", "0",141 "0", "-1", "0",142 "0", "0", "1"143};144 145static const struct property_entry chuwi_hi8_bma250e_props[] = {146 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),147 { }148};149 150static const struct software_node chuwi_hi8_bma250e_node = {151 .properties = chuwi_hi8_bma250e_props,152};153 154static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {155 {156 /* Silead touchscreen */157 .board_info = {158 .type = "gsl1680",159 .addr = 0x40,160 .swnode = &chuwi_hi8_gsl1680_node,161 },162 .adapter_path = "\\_SB_.I2C4",163 .irq_data = {164 .type = X86_ACPI_IRQ_TYPE_APIC,165 .index = 0x44,166 .trigger = ACPI_EDGE_SENSITIVE,167 .polarity = ACPI_ACTIVE_HIGH,168 },169 }, {170 /* BMA250E accelerometer */171 .board_info = {172 .type = "bma250e",173 .addr = 0x18,174 .swnode = &chuwi_hi8_bma250e_node,175 },176 .adapter_path = "\\_SB_.I2C3",177 .irq_data = {178 .type = X86_ACPI_IRQ_TYPE_GPIOINT,179 .chip = "INT33FC:02",180 .index = 23,181 .trigger = ACPI_LEVEL_SENSITIVE,182 .polarity = ACPI_ACTIVE_HIGH,183 .con_id = "bma250e_irq",184 },185 },186};187 188static int __init chuwi_hi8_init(struct device *dev)189{190 /*191 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()192 * breaking the touchscreen + logging various errors when the Windows193 * BIOS is used.194 */195 if (acpi_dev_present("MSSL0001", NULL, 1))196 return -ENODEV;197 198 return 0;199}200 201const 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,205};206 207/*208 * Cyberbook T116 Android version209 * This comes in both Windows and Android versions and even on Android210 * the DSDT is mostly sane. This tablet has 2 extra general purpose buttons211 * in the button row with the power + volume-buttons labeled P and F.212 * Use the x86-android-tablets infra to create a gpio-keys device for these.213 */214static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {215 {216 .button = {217 .code = KEY_PROG1,218 .active_low = true,219 .desc = "prog1_key",220 .type = EV_KEY,221 .wakeup = false,222 .debounce_interval = 50,223 },224 .chip = "INT33FF:00",225 .pin = 30,226 },227 {228 .button = {229 .code = KEY_PROG2,230 .active_low = true,231 .desc = "prog2_key",232 .type = EV_KEY,233 .wakeup = false,234 .debounce_interval = 50,235 },236 .chip = "INT33FF:03",237 .pin = 48,238 },239};240 241const struct x86_dev_info cyberbook_t116_info __initconst = {242 .gpio_button = cyberbook_t116_buttons,243 .gpio_button_count = ARRAY_SIZE(cyberbook_t116_buttons),244};245 246#define CZC_EC_EXTRA_PORT 0x68247#define CZC_EC_ANDROID_KEYS 0x63248 249static int __init czc_p10t_init(struct device *dev)250{251 /*252 * The device boots up in "Windows 7" mode, when the home button sends a253 * Windows specific key sequence (Left Meta + D) and the second button254 * sends an unknown one while also toggling the Radio Kill Switch.255 * This is a surprising behavior when the second button is labeled "Back".256 *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 just259 * set bit 6 on address 0x96 in the EC region; switching the bit directly260 * seems to achieve the same result. It uses a "p10t_switcher" to do the261 * job. It doesn't seem to be able to do anything else, and no other use262 * of the port 0x68 is known.263 *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 back266 * button only sends a scancode without toggling the kill switch.267 * The scancode can then be mapped either to Back or RF Kill functionality268 * in userspace, depending on how the button is labeled on that particular269 * model.270 */271 outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);272 return 0;273}274 275const struct x86_dev_info czc_p10t __initconst = {276 .init = czc_p10t_init,277};278 279/* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */280static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {281 "0", "1", "0",282 "1", "0", "0",283 "0", "0", "1"284};285 286static const struct property_entry medion_lifetab_s10346_accel_props[] = {287 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),288 { }289};290 291static const struct software_node medion_lifetab_s10346_accel_node = {292 .properties = medion_lifetab_s10346_accel_props,293};294 295/* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */296static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {297 PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),298 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),299 { }300};301 302static const struct software_node medion_lifetab_s10346_touchscreen_node = {303 .properties = medion_lifetab_s10346_touchscreen_props,304};305 306static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {307 {308 /* kxtj21009 accelerometer */309 .board_info = {310 .type = "kxtj21009",311 .addr = 0x0f,312 .dev_name = "kxtj21009",313 .swnode = &medion_lifetab_s10346_accel_node,314 },315 .adapter_path = "\\_SB_.I2C3",316 .irq_data = {317 .type = X86_ACPI_IRQ_TYPE_GPIOINT,318 .chip = "INT33FC:02",319 .index = 23,320 .trigger = ACPI_EDGE_SENSITIVE,321 .polarity = ACPI_ACTIVE_HIGH,322 .con_id = "kxtj21009_irq",323 },324 }, {325 /* goodix touchscreen */326 .board_info = {327 .type = "GDIX1001:00",328 .addr = 0x14,329 .dev_name = "goodix_ts",330 .swnode = &medion_lifetab_s10346_touchscreen_node,331 },332 .adapter_path = "\\_SB_.I2C4",333 .irq_data = {334 .type = X86_ACPI_IRQ_TYPE_APIC,335 .index = 0x44,336 .trigger = ACPI_EDGE_SENSITIVE,337 .polarity = ACPI_ACTIVE_LOW,338 },339 },340};341 342static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {343 .dev_id = "i2c-goodix_ts",344 .table = {345 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),346 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),347 { }348 },349};350 351static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {352 &medion_lifetab_s10346_goodix_gpios,353 NULL354};355 356const 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,360};361 362/* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */363static const char * const nextbook_ares8_accel_mount_matrix[] = {364 "0", "-1", "0",365 "-1", "0", "0",366 "0", "0", "1"367};368 369static const struct property_entry nextbook_ares8_accel_props[] = {370 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),371 { }372};373 374static const struct software_node nextbook_ares8_accel_node = {375 .properties = nextbook_ares8_accel_props,376};377 378static const struct property_entry nextbook_ares8_touchscreen_props[] = {379 PROPERTY_ENTRY_U32("touchscreen-size-x", 800),380 PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),381 { }382};383 384static const struct software_node nextbook_ares8_touchscreen_node = {385 .properties = nextbook_ares8_touchscreen_props,386};387 388static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {389 {390 /* Freescale MMA8653FC accelerometer */391 .board_info = {392 .type = "mma8653",393 .addr = 0x1d,394 .dev_name = "mma8653",395 .swnode = &nextbook_ares8_accel_node,396 },397 .adapter_path = "\\_SB_.I2C3",398 }, {399 /* FT5416DQ9 touchscreen controller */400 .board_info = {401 .type = "edt-ft5x06",402 .addr = 0x38,403 .dev_name = "ft5416",404 .swnode = &nextbook_ares8_touchscreen_node,405 },406 .adapter_path = "\\_SB_.I2C4",407 .irq_data = {408 .type = X86_ACPI_IRQ_TYPE_GPIOINT,409 .chip = "INT33FC:02",410 .index = 3,411 .trigger = ACPI_EDGE_SENSITIVE,412 .polarity = ACPI_ACTIVE_LOW,413 .con_id = "ft5416_irq",414 },415 },416};417 418static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {419 &int3496_reference_gpios,420 NULL421};422 423const 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,427 .pdev_count = 1,428 .gpiod_lookup_tables = nextbook_ares8_gpios,429};430 431/* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */432static const char * const nextbook_ares8a_accel_mount_matrix[] = {433 "1", "0", "0",434 "0", "-1", "0",435 "0", "0", "1"436};437 438static const struct property_entry nextbook_ares8a_accel_props[] = {439 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),440 { }441};442 443static const struct software_node nextbook_ares8a_accel_node = {444 .properties = nextbook_ares8a_accel_props,445};446 447static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {448 {449 /* Freescale MMA8653FC accelerometer */450 .board_info = {451 .type = "mma8653",452 .addr = 0x1d,453 .dev_name = "mma8653",454 .swnode = &nextbook_ares8a_accel_node,455 },456 .adapter_path = "\\_SB_.PCI0.I2C3",457 }, {458 /* FT5416DQ9 touchscreen controller */459 .board_info = {460 .type = "edt-ft5x06",461 .addr = 0x38,462 .dev_name = "ft5416",463 .swnode = &nextbook_ares8_touchscreen_node,464 },465 .adapter_path = "\\_SB_.PCI0.I2C6",466 .irq_data = {467 .type = X86_ACPI_IRQ_TYPE_GPIOINT,468 .chip = "INT33FF:01",469 .index = 17,470 .trigger = ACPI_EDGE_SENSITIVE,471 .polarity = ACPI_ACTIVE_LOW,472 .con_id = "ft5416_irq",473 },474 },475};476 477static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = {478 .dev_id = "i2c-ft5416",479 .table = {480 GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW),481 { }482 },483};484 485static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = {486 &nextbook_ares8a_ft5416_gpios,487 NULL488};489 490const 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,494};495 496/*497 * Peaq C1010498 * 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 to500 * use the broken WMI interface, instantiate a gpio-keys device for this.501 */502static const struct x86_gpio_button peaq_c1010_button __initconst = {503 .button = {504 .code = KEY_SOUND,505 .active_low = true,506 .desc = "dolby_key",507 .type = EV_KEY,508 .wakeup = false,509 .debounce_interval = 50,510 },511 .chip = "INT33FC:00",512 .pin = 3,513};514 515const struct x86_dev_info peaq_c1010_info __initconst = {516 .gpio_button = &peaq_c1010_button,517 .gpio_button_count = 1,518};519 520/*521 * Whitelabel (sold as various brands) TM800A550L tablets.522 * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices523 * (removed through acpi_quirk_skip_i2c_client_enumeration()) and524 * the touchscreen firmware node has the wrong GPIOs.525 */526static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {527 "-1", "0", "0",528 "0", "1", "0",529 "0", "0", "1"530};531 532static const struct property_entry whitelabel_tm800a550l_accel_props[] = {533 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),534 { }535};536 537static const struct software_node whitelabel_tm800a550l_accel_node = {538 .properties = whitelabel_tm800a550l_accel_props,539};540 541static 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),545 { }546};547 548static const struct software_node whitelabel_tm800a550l_goodix_node = {549 .properties = whitelabel_tm800a550l_goodix_props,550};551 552static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {553 {554 /* goodix touchscreen */555 .board_info = {556 .type = "GDIX1001:00",557 .addr = 0x14,558 .dev_name = "goodix_ts",559 .swnode = &whitelabel_tm800a550l_goodix_node,560 },561 .adapter_path = "\\_SB_.I2C2",562 .irq_data = {563 .type = X86_ACPI_IRQ_TYPE_APIC,564 .index = 0x44,565 .trigger = ACPI_EDGE_SENSITIVE,566 .polarity = ACPI_ACTIVE_HIGH,567 },568 }, {569 /* kxcj91008 accelerometer */570 .board_info = {571 .type = "kxcj91008",572 .addr = 0x0f,573 .dev_name = "kxcj91008",574 .swnode = &whitelabel_tm800a550l_accel_node,575 },576 .adapter_path = "\\_SB_.I2C3",577 },578};579 580static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {581 .dev_id = "i2c-goodix_ts",582 .table = {583 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),584 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),585 { }586 },587};588 589static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {590 &whitelabel_tm800a550l_goodix_gpios,591 NULL592};593 594const 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,598};599 600/*601 * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node602 * with three subnodes for each color (B/G/R). The RGB LED node is named603 * "multi-led" to align with the name in the device tree.604 */605 606/* Main firmware node for ktd2026 */607static const struct software_node ktd2026_node = {608 .name = "ktd2026",609};610 611static 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"),616 { }617};618 619static const struct software_node ktd2026_rgb_led_node = {620 .name = "multi-led",621 .properties = ktd2026_rgb_led_props,622 .parent = &ktd2026_node,623};624 625static const struct property_entry ktd2026_blue_led_props[] = {626 PROPERTY_ENTRY_U32("reg", 0),627 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),628 { }629};630 631static const struct software_node ktd2026_blue_led_node = {632 .properties = ktd2026_blue_led_props,633 .parent = &ktd2026_rgb_led_node,634};635 636static const struct property_entry ktd2026_green_led_props[] = {637 PROPERTY_ENTRY_U32("reg", 1),638 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),639 { }640};641 642static const struct software_node ktd2026_green_led_node = {643 .properties = ktd2026_green_led_props,644 .parent = &ktd2026_rgb_led_node,645};646 647static const struct property_entry ktd2026_red_led_props[] = {648 PROPERTY_ENTRY_U32("reg", 2),649 PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),650 { }651};652 653static const struct software_node ktd2026_red_led_node = {654 .properties = ktd2026_red_led_props,655 .parent = &ktd2026_rgb_led_node,656};657 658static const struct software_node *ktd2026_node_group[] = {659 &ktd2026_node,660 &ktd2026_rgb_led_node,661 &ktd2026_red_led_node,662 &ktd2026_green_led_node,663 &ktd2026_blue_led_node,664 NULL665};666 667/*668 * For the LEDs which backlight the Menu / Home / Back capacitive buttons on669 * the bottom bezel. These are attached to a TPS61158 LED controller which670 * is controlled by the "pwm_soc_lpss_2" PWM output.671 */672#define XIAOMI_MIPAD2_LED_PERIOD_NS 19200673#define XIAOMI_MIPAD2_LED_MAX_DUTY_NS 6000 /* From Android kernel */674 675static struct pwm_device *xiaomi_mipad2_led_pwm;676 677static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,678 enum led_brightness val)679{680 struct pwm_state state = {681 .period = XIAOMI_MIPAD2_LED_PERIOD_NS,682 .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,683 /* Always set PWM enabled to avoid the pin floating */684 .enabled = true,685 };686 687 return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);688}689 690static int __init xiaomi_mipad2_init(struct device *dev)691{692 struct led_classdev *led_cdev;693 int ret;694 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");698 699 led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);700 if (!led_cdev)701 return -ENOMEM;702 703 led_cdev->name = "mipad2:white:touch-buttons-backlight";704 led_cdev->max_brightness = LED_FULL;705 led_cdev->default_trigger = "input-events";706 led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;707 /* Turn LED off during suspend */708 led_cdev->flags = LED_CORE_SUSPENDRESUME;709 710 ret = devm_led_classdev_register(dev, led_cdev);711 if (ret)712 return dev_err_probe(dev, ret, "registering LED\n");713 714 return software_node_register_node_group(ktd2026_node_group);715}716 717static void xiaomi_mipad2_exit(void)718{719 software_node_unregister_node_group(ktd2026_node_group);720}721 722/*723 * If the EFI bootloader is not Xiaomi's own signed Android loader, then the724 * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing725 * a bunch of devices to be hidden.726 *727 * This takes care of instantiating the hidden devices manually.728 */729static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {730 {731 /* BQ27520 fuel-gauge */732 .board_info = {733 .type = "bq27520",734 .addr = 0x55,735 .dev_name = "bq27520",736 .swnode = &fg_bq25890_supply_node,737 },738 .adapter_path = "\\_SB_.PCI0.I2C1",739 }, {740 /* KTD2026 RGB notification LED controller */741 .board_info = {742 .type = "ktd2026",743 .addr = 0x30,744 .dev_name = "ktd2026",745 .swnode = &ktd2026_node,746 },747 .adapter_path = "\\_SB_.PCI0.I2C3",748 },749};750 751const 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,756};757