Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.17-rc3 955 lines 26 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 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 Hans de Goede <hdegoede@redhat.com> 9 */ 10 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 13#include <linux/acpi.h> 14#include <linux/dmi.h> 15#include <linux/gpio/consumer.h> 16#include <linux/gpio/driver.h> 17#include <linux/gpio/machine.h> 18#include <linux/i2c.h> 19#include <linux/irq.h> 20#include <linux/irqdomain.h> 21#include <linux/module.h> 22#include <linux/mod_devicetable.h> 23#include <linux/platform_device.h> 24#include <linux/power/bq24190_charger.h> 25#include <linux/serdev.h> 26#include <linux/string.h> 27/* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */ 28#include "../../gpio/gpiolib.h" 29#include "../../gpio/gpiolib-acpi.h" 30 31/* 32 * Helper code to get Linux IRQ numbers given a description of the IRQ source 33 * (either IOAPIC index, or GPIO chip name + pin-number). 34 */ 35enum x86_acpi_irq_type { 36 X86_ACPI_IRQ_TYPE_NONE, 37 X86_ACPI_IRQ_TYPE_APIC, 38 X86_ACPI_IRQ_TYPE_GPIOINT, 39 X86_ACPI_IRQ_TYPE_PMIC, 40}; 41 42struct x86_acpi_irq_data { 43 char *chip; /* GPIO chip label (GPIOINT) or PMIC ACPI path (PMIC) */ 44 enum x86_acpi_irq_type type; 45 enum irq_domain_bus_token domain; 46 int index; 47 int trigger; /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */ 48 int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */ 49}; 50 51static int gpiochip_find_match_label(struct gpio_chip *gc, void *data) 52{ 53 return gc->label && !strcmp(gc->label, data); 54} 55 56static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data) 57{ 58 struct irq_fwspec fwspec = { }; 59 struct irq_domain *domain; 60 struct acpi_device *adev; 61 struct gpio_desc *gpiod; 62 struct gpio_chip *chip; 63 unsigned int irq_type; 64 acpi_handle handle; 65 acpi_status status; 66 int irq, ret; 67 68 switch (data->type) { 69 case X86_ACPI_IRQ_TYPE_APIC: 70 irq = acpi_register_gsi(NULL, data->index, data->trigger, data->polarity); 71 if (irq < 0) 72 pr_err("error %d getting APIC IRQ %d\n", irq, data->index); 73 74 return irq; 75 case X86_ACPI_IRQ_TYPE_GPIOINT: 76 /* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */ 77 chip = gpiochip_find(data->chip, gpiochip_find_match_label); 78 if (!chip) { 79 pr_err("error cannot find GPIO chip %s\n", data->chip); 80 return -ENODEV; 81 } 82 83 gpiod = gpiochip_get_desc(chip, data->index); 84 if (IS_ERR(gpiod)) { 85 ret = PTR_ERR(gpiod); 86 pr_err("error %d getting GPIO %s %d\n", ret, data->chip, data->index); 87 return ret; 88 } 89 90 irq = gpiod_to_irq(gpiod); 91 if (irq < 0) { 92 pr_err("error %d getting IRQ %s %d\n", irq, data->chip, data->index); 93 return irq; 94 } 95 96 irq_type = acpi_dev_get_irq_type(data->trigger, data->polarity); 97 if (irq_type != IRQ_TYPE_NONE && irq_type != irq_get_trigger_type(irq)) 98 irq_set_irq_type(irq, irq_type); 99 100 return irq; 101 case X86_ACPI_IRQ_TYPE_PMIC: 102 status = acpi_get_handle(NULL, data->chip, &handle); 103 if (ACPI_FAILURE(status)) { 104 pr_err("error could not get %s handle\n", data->chip); 105 return -ENODEV; 106 } 107 108 acpi_bus_get_device(handle, &adev); 109 if (!adev) { 110 pr_err("error could not get %s adev\n", data->chip); 111 return -ENODEV; 112 } 113 114 fwspec.fwnode = acpi_fwnode_handle(adev); 115 domain = irq_find_matching_fwspec(&fwspec, data->domain); 116 if (!domain) { 117 pr_err("error could not find IRQ domain for %s\n", data->chip); 118 return -ENODEV; 119 } 120 121 return irq_create_mapping(domain, data->index); 122 default: 123 return 0; 124 } 125} 126 127struct x86_i2c_client_info { 128 struct i2c_board_info board_info; 129 char *adapter_path; 130 struct x86_acpi_irq_data irq_data; 131}; 132 133struct x86_serdev_info { 134 const char *ctrl_hid; 135 const char *ctrl_uid; 136 const char *ctrl_devname; 137 /* 138 * ATM the serdev core only supports of or ACPI matching; and sofar all 139 * Android x86 tablets DSDTs have usable serdev nodes, but sometimes 140 * under the wrong controller. So we just tie the existing serdev ACPI 141 * node to the right controller. 142 */ 143 const char *serdev_hid; 144}; 145 146struct x86_dev_info { 147 char *invalid_aei_gpiochip; 148 const char * const *modules; 149 struct gpiod_lookup_table * const *gpiod_lookup_tables; 150 const struct x86_i2c_client_info *i2c_client_info; 151 const struct platform_device_info *pdev_info; 152 const struct x86_serdev_info *serdev_info; 153 int i2c_client_count; 154 int pdev_count; 155 int serdev_count; 156 int (*init)(void); 157 void (*exit)(void); 158}; 159 160/* Generic / shared bq24190 settings */ 161static const char * const bq24190_suppliers[] = { "tusb1210-psy" }; 162 163static const struct property_entry bq24190_props[] = { 164 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_suppliers), 165 PROPERTY_ENTRY_BOOL("omit-battery-class"), 166 PROPERTY_ENTRY_BOOL("disable-reset"), 167 { } 168}; 169 170static const struct software_node bq24190_node = { 171 .properties = bq24190_props, 172}; 173 174/* For enableing the bq24190 5V boost based on id-pin */ 175static struct regulator_consumer_supply intel_int3496_consumer = { 176 .supply = "vbus", 177 .dev_name = "intel-int3496", 178}; 179 180static const struct regulator_init_data bq24190_vbus_init_data = { 181 .constraints = { 182 .name = "bq24190_vbus", 183 .valid_ops_mask = REGULATOR_CHANGE_STATUS, 184 }, 185 .consumer_supplies = &intel_int3496_consumer, 186 .num_consumer_supplies = 1, 187}; 188 189static struct bq24190_platform_data bq24190_pdata = { 190 .regulator_init_data = &bq24190_vbus_init_data, 191}; 192 193static const char * const bq24190_modules[] __initconst = { 194 "intel_crystal_cove_charger", /* For the bq24190 IRQ */ 195 "bq24190_charger", /* For the Vbus regulator for intel-int3496 */ 196 NULL 197}; 198 199/* Generic pdevs array and gpio-lookups for micro USB ID pin handling */ 200static const struct platform_device_info int3496_pdevs[] __initconst = { 201 { 202 /* For micro USB ID pin handling */ 203 .name = "intel-int3496", 204 .id = PLATFORM_DEVID_NONE, 205 }, 206}; 207 208static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = { 209 .dev_id = "intel-int3496", 210 .table = { 211 GPIO_LOOKUP("INT33FC:02", 22, "id", GPIO_ACTIVE_HIGH), 212 { } 213 }, 214}; 215 216/* Asus ME176C tablets have an Android factory img with everything hardcoded */ 217static const char * const asus_me176c_accel_mount_matrix[] = { 218 "-1", "0", "0", 219 "0", "1", "0", 220 "0", "0", "1" 221}; 222 223static const struct property_entry asus_me176c_accel_props[] = { 224 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", asus_me176c_accel_mount_matrix), 225 { } 226}; 227 228static const struct software_node asus_me176c_accel_node = { 229 .properties = asus_me176c_accel_props, 230}; 231 232static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = { 233 { 234 /* bq24190 battery charger */ 235 .board_info = { 236 .type = "bq24190", 237 .addr = 0x6b, 238 .dev_name = "bq24190", 239 .swnode = &bq24190_node, 240 .platform_data = &bq24190_pdata, 241 }, 242 .adapter_path = "\\_SB_.I2C1", 243 .irq_data = { 244 .type = X86_ACPI_IRQ_TYPE_PMIC, 245 .chip = "\\_SB_.I2C7.PMIC", 246 .domain = DOMAIN_BUS_WAKEUP, 247 .index = 0, 248 }, 249 }, { 250 /* ug3105 battery monitor */ 251 .board_info = { 252 .type = "ug3105", 253 .addr = 0x70, 254 .dev_name = "ug3105", 255 }, 256 .adapter_path = "\\_SB_.I2C1", 257 }, { 258 /* ak09911 compass */ 259 .board_info = { 260 .type = "ak09911", 261 .addr = 0x0c, 262 .dev_name = "ak09911", 263 }, 264 .adapter_path = "\\_SB_.I2C5", 265 }, { 266 /* kxtj21009 accel */ 267 .board_info = { 268 .type = "kxtj21009", 269 .addr = 0x0f, 270 .dev_name = "kxtj21009", 271 .swnode = &asus_me176c_accel_node, 272 }, 273 .adapter_path = "\\_SB_.I2C5", 274 }, { 275 /* goodix touchscreen */ 276 .board_info = { 277 .type = "GDIX1001:00", 278 .addr = 0x14, 279 .dev_name = "goodix_ts", 280 }, 281 .adapter_path = "\\_SB_.I2C6", 282 .irq_data = { 283 .type = X86_ACPI_IRQ_TYPE_APIC, 284 .index = 0x45, 285 .trigger = ACPI_EDGE_SENSITIVE, 286 .polarity = ACPI_ACTIVE_LOW, 287 }, 288 }, 289}; 290 291static const struct x86_serdev_info asus_me176c_serdevs[] __initconst = { 292 { 293 .ctrl_hid = "80860F0A", 294 .ctrl_uid = "2", 295 .ctrl_devname = "serial0", 296 .serdev_hid = "BCM2E3A", 297 }, 298}; 299 300static struct gpiod_lookup_table asus_me176c_goodix_gpios = { 301 .dev_id = "i2c-goodix_ts", 302 .table = { 303 GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_HIGH), 304 GPIO_LOOKUP("INT33FC:02", 28, "irq", GPIO_ACTIVE_HIGH), 305 { } 306 }, 307}; 308 309static struct gpiod_lookup_table * const asus_me176c_gpios[] = { 310 &int3496_gpo2_pin22_gpios, 311 &asus_me176c_goodix_gpios, 312 NULL 313}; 314 315static const struct x86_dev_info asus_me176c_info __initconst = { 316 .i2c_client_info = asus_me176c_i2c_clients, 317 .i2c_client_count = ARRAY_SIZE(asus_me176c_i2c_clients), 318 .pdev_info = int3496_pdevs, 319 .pdev_count = ARRAY_SIZE(int3496_pdevs), 320 .serdev_info = asus_me176c_serdevs, 321 .serdev_count = ARRAY_SIZE(asus_me176c_serdevs), 322 .gpiod_lookup_tables = asus_me176c_gpios, 323 .modules = bq24190_modules, 324 .invalid_aei_gpiochip = "INT33FC:02", 325}; 326 327/* Asus TF103C tablets have an Android factory img with everything hardcoded */ 328static const char * const asus_tf103c_accel_mount_matrix[] = { 329 "0", "-1", "0", 330 "-1", "0", "0", 331 "0", "0", "1" 332}; 333 334static const struct property_entry asus_tf103c_accel_props[] = { 335 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", asus_tf103c_accel_mount_matrix), 336 { } 337}; 338 339static const struct software_node asus_tf103c_accel_node = { 340 .properties = asus_tf103c_accel_props, 341}; 342 343static const struct property_entry asus_tf103c_touchscreen_props[] = { 344 PROPERTY_ENTRY_STRING("compatible", "atmel,atmel_mxt_ts"), 345 { } 346}; 347 348static const struct software_node asus_tf103c_touchscreen_node = { 349 .properties = asus_tf103c_touchscreen_props, 350}; 351 352static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst = { 353 { 354 /* bq24190 battery charger */ 355 .board_info = { 356 .type = "bq24190", 357 .addr = 0x6b, 358 .dev_name = "bq24190", 359 .swnode = &bq24190_node, 360 .platform_data = &bq24190_pdata, 361 }, 362 .adapter_path = "\\_SB_.I2C1", 363 .irq_data = { 364 .type = X86_ACPI_IRQ_TYPE_PMIC, 365 .chip = "\\_SB_.I2C7.PMIC", 366 .domain = DOMAIN_BUS_WAKEUP, 367 .index = 0, 368 }, 369 }, { 370 /* ug3105 battery monitor */ 371 .board_info = { 372 .type = "ug3105", 373 .addr = 0x70, 374 .dev_name = "ug3105", 375 }, 376 .adapter_path = "\\_SB_.I2C1", 377 }, { 378 /* ak09911 compass */ 379 .board_info = { 380 .type = "ak09911", 381 .addr = 0x0c, 382 .dev_name = "ak09911", 383 }, 384 .adapter_path = "\\_SB_.I2C5", 385 }, { 386 /* kxtj21009 accel */ 387 .board_info = { 388 .type = "kxtj21009", 389 .addr = 0x0f, 390 .dev_name = "kxtj21009", 391 .swnode = &asus_tf103c_accel_node, 392 }, 393 .adapter_path = "\\_SB_.I2C5", 394 }, { 395 /* atmel touchscreen */ 396 .board_info = { 397 .type = "atmel_mxt_ts", 398 .addr = 0x4a, 399 .dev_name = "atmel_mxt_ts", 400 .swnode = &asus_tf103c_touchscreen_node, 401 }, 402 .adapter_path = "\\_SB_.I2C6", 403 .irq_data = { 404 .type = X86_ACPI_IRQ_TYPE_GPIOINT, 405 .chip = "INT33FC:02", 406 .index = 28, 407 .trigger = ACPI_EDGE_SENSITIVE, 408 .polarity = ACPI_ACTIVE_LOW, 409 }, 410 }, 411}; 412 413static struct gpiod_lookup_table * const asus_tf103c_gpios[] = { 414 &int3496_gpo2_pin22_gpios, 415 NULL 416}; 417 418static const struct x86_dev_info asus_tf103c_info __initconst = { 419 .i2c_client_info = asus_tf103c_i2c_clients, 420 .i2c_client_count = ARRAY_SIZE(asus_tf103c_i2c_clients), 421 .pdev_info = int3496_pdevs, 422 .pdev_count = ARRAY_SIZE(int3496_pdevs), 423 .gpiod_lookup_tables = asus_tf103c_gpios, 424 .modules = bq24190_modules, 425 .invalid_aei_gpiochip = "INT33FC:02", 426}; 427 428/* 429 * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT 430 * contains a whole bunch of bogus ACPI I2C devices and is missing entries 431 * for the touchscreen and the accelerometer. 432 */ 433static const struct property_entry chuwi_hi8_gsl1680_props[] = { 434 PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), 435 PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), 436 PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), 437 PROPERTY_ENTRY_BOOL("silead,home-button"), 438 PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), 439 { } 440}; 441 442static const struct software_node chuwi_hi8_gsl1680_node = { 443 .properties = chuwi_hi8_gsl1680_props, 444}; 445 446static const char * const chuwi_hi8_mount_matrix[] = { 447 "1", "0", "0", 448 "0", "-1", "0", 449 "0", "0", "1" 450}; 451 452static const struct property_entry chuwi_hi8_bma250e_props[] = { 453 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix), 454 { } 455}; 456 457static const struct software_node chuwi_hi8_bma250e_node = { 458 .properties = chuwi_hi8_bma250e_props, 459}; 460 461static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = { 462 { 463 /* Silead touchscreen */ 464 .board_info = { 465 .type = "gsl1680", 466 .addr = 0x40, 467 .swnode = &chuwi_hi8_gsl1680_node, 468 }, 469 .adapter_path = "\\_SB_.I2C4", 470 .irq_data = { 471 .type = X86_ACPI_IRQ_TYPE_APIC, 472 .index = 0x44, 473 .trigger = ACPI_EDGE_SENSITIVE, 474 .polarity = ACPI_ACTIVE_HIGH, 475 }, 476 }, { 477 /* BMA250E accelerometer */ 478 .board_info = { 479 .type = "bma250e", 480 .addr = 0x18, 481 .swnode = &chuwi_hi8_bma250e_node, 482 }, 483 .adapter_path = "\\_SB_.I2C3", 484 .irq_data = { 485 .type = X86_ACPI_IRQ_TYPE_GPIOINT, 486 .chip = "INT33FC:02", 487 .index = 23, 488 .trigger = ACPI_LEVEL_SENSITIVE, 489 .polarity = ACPI_ACTIVE_HIGH, 490 }, 491 }, 492}; 493 494static const struct x86_dev_info chuwi_hi8_info __initconst = { 495 .i2c_client_info = chuwi_hi8_i2c_clients, 496 .i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients), 497}; 498 499#define CZC_EC_EXTRA_PORT 0x68 500#define CZC_EC_ANDROID_KEYS 0x63 501 502static int __init czc_p10t_init(void) 503{ 504 /* 505 * The device boots up in "Windows 7" mode, when the home button sends a 506 * Windows specific key sequence (Left Meta + D) and the second button 507 * sends an unknown one while also toggling the Radio Kill Switch. 508 * This is a surprising behavior when the second button is labeled "Back". 509 * 510 * The vendor-supplied Android-x86 build switches the device to a "Android" 511 * mode by writing value 0x63 to the I/O port 0x68. This just seems to just 512 * set bit 6 on address 0x96 in the EC region; switching the bit directly 513 * seems to achieve the same result. It uses a "p10t_switcher" to do the 514 * job. It doesn't seem to be able to do anything else, and no other use 515 * of the port 0x68 is known. 516 * 517 * In the Android mode, the home button sends just a single scancode, 518 * which can be handled in Linux userspace more reasonably and the back 519 * button only sends a scancode without toggling the kill switch. 520 * The scancode can then be mapped either to Back or RF Kill functionality 521 * in userspace, depending on how the button is labeled on that particular 522 * model. 523 */ 524 outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT); 525 return 0; 526} 527 528static const struct x86_dev_info czc_p10t __initconst = { 529 .init = czc_p10t_init, 530}; 531 532/* 533 * Whitelabel (sold as various brands) TM800A550L tablets. 534 * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices 535 * (removed through acpi_quirk_skip_i2c_client_enumeration()) and 536 * the touchscreen fwnode has the wrong GPIOs. 537 */ 538static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = { 539 "-1", "0", "0", 540 "0", "1", "0", 541 "0", "0", "1" 542}; 543 544static const struct property_entry whitelabel_tm800a550l_accel_props[] = { 545 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix), 546 { } 547}; 548 549static const struct software_node whitelabel_tm800a550l_accel_node = { 550 .properties = whitelabel_tm800a550l_accel_props, 551}; 552 553static const struct property_entry whitelabel_tm800a550l_goodix_props[] = { 554 PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"), 555 PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"), 556 PROPERTY_ENTRY_U32("goodix,main-clk", 54), 557 { } 558}; 559 560static const struct software_node whitelabel_tm800a550l_goodix_node = { 561 .properties = whitelabel_tm800a550l_goodix_props, 562}; 563 564static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = { 565 { 566 /* goodix touchscreen */ 567 .board_info = { 568 .type = "GDIX1001:00", 569 .addr = 0x14, 570 .dev_name = "goodix_ts", 571 .swnode = &whitelabel_tm800a550l_goodix_node, 572 }, 573 .adapter_path = "\\_SB_.I2C2", 574 .irq_data = { 575 .type = X86_ACPI_IRQ_TYPE_APIC, 576 .index = 0x44, 577 .trigger = ACPI_EDGE_SENSITIVE, 578 .polarity = ACPI_ACTIVE_HIGH, 579 }, 580 }, { 581 /* kxcj91008 accel */ 582 .board_info = { 583 .type = "kxcj91008", 584 .addr = 0x0f, 585 .dev_name = "kxcj91008", 586 .swnode = &whitelabel_tm800a550l_accel_node, 587 }, 588 .adapter_path = "\\_SB_.I2C3", 589 }, 590}; 591 592static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = { 593 .dev_id = "i2c-goodix_ts", 594 .table = { 595 GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH), 596 GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH), 597 { } 598 }, 599}; 600 601static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = { 602 &whitelabel_tm800a550l_goodix_gpios, 603 NULL 604}; 605 606static const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { 607 .i2c_client_info = whitelabel_tm800a550l_i2c_clients, 608 .i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients), 609 .gpiod_lookup_tables = whitelabel_tm800a550l_gpios, 610}; 611 612/* 613 * If the EFI bootloader is not Xiaomi's own signed Android loader, then the 614 * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing 615 * a bunch of devices to be hidden. 616 * 617 * This takes care of instantiating the hidden devices manually. 618 */ 619static const char * const bq27520_suppliers[] = { "bq25890-charger" }; 620 621static const struct property_entry bq27520_props[] = { 622 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27520_suppliers), 623 { } 624}; 625 626static const struct software_node bq27520_node = { 627 .properties = bq27520_props, 628}; 629 630static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = { 631 { 632 /* BQ27520 fuel-gauge */ 633 .board_info = { 634 .type = "bq27520", 635 .addr = 0x55, 636 .dev_name = "bq27520", 637 .swnode = &bq27520_node, 638 }, 639 .adapter_path = "\\_SB_.PCI0.I2C1", 640 }, { 641 /* KTD2026 RGB notification LED controller */ 642 .board_info = { 643 .type = "ktd2026", 644 .addr = 0x30, 645 .dev_name = "ktd2026", 646 }, 647 .adapter_path = "\\_SB_.PCI0.I2C3", 648 }, 649}; 650 651static const struct x86_dev_info xiaomi_mipad2_info __initconst = { 652 .i2c_client_info = xiaomi_mipad2_i2c_clients, 653 .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients), 654}; 655 656static const struct dmi_system_id x86_android_tablet_ids[] __initconst = { 657 { 658 /* Asus MeMO Pad 7 ME176C */ 659 .matches = { 660 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 661 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ME176C"), 662 }, 663 .driver_data = (void *)&asus_me176c_info, 664 }, 665 { 666 /* Asus TF103C */ 667 .matches = { 668 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 669 DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"), 670 }, 671 .driver_data = (void *)&asus_tf103c_info, 672 }, 673 { 674 /* Chuwi Hi8 (CWI509) */ 675 .matches = { 676 DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), 677 DMI_MATCH(DMI_BOARD_NAME, "BYT-PA03C"), 678 DMI_MATCH(DMI_SYS_VENDOR, "ilife"), 679 DMI_MATCH(DMI_PRODUCT_NAME, "S806"), 680 }, 681 .driver_data = (void *)&chuwi_hi8_info, 682 }, 683 { 684 /* CZC P10T */ 685 .ident = "CZC ODEON TPC-10 (\"P10T\")", 686 .matches = { 687 DMI_MATCH(DMI_SYS_VENDOR, "CZC"), 688 DMI_MATCH(DMI_PRODUCT_NAME, "ODEON*TPC-10"), 689 }, 690 .driver_data = (void *)&czc_p10t, 691 }, 692 { 693 /* A variant of CZC P10T */ 694 .ident = "ViewSonic ViewPad 10", 695 .matches = { 696 DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"), 697 DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"), 698 }, 699 .driver_data = (void *)&czc_p10t, 700 }, 701 { 702 /* Whitelabel (sold as various brands) TM800A550L */ 703 .matches = { 704 DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), 705 DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), 706 /* Above strings are too generic, also match on BIOS version */ 707 DMI_MATCH(DMI_BIOS_VERSION, "ZY-8-BI-PX4S70VTR400-X423B-005-D"), 708 }, 709 .driver_data = (void *)&whitelabel_tm800a550l_info, 710 }, 711 { 712 /* Xiaomi Mi Pad 2 */ 713 .matches = { 714 DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), 715 DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), 716 }, 717 .driver_data = (void *)&xiaomi_mipad2_info, 718 }, 719 { } 720}; 721MODULE_DEVICE_TABLE(dmi, x86_android_tablet_ids); 722 723static int i2c_client_count; 724static int pdev_count; 725static int serdev_count; 726static struct i2c_client **i2c_clients; 727static struct platform_device **pdevs; 728static struct serdev_device **serdevs; 729static struct gpiod_lookup_table * const *gpiod_lookup_tables; 730static void (*exit_handler)(void); 731 732static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info, 733 int idx) 734{ 735 const struct x86_i2c_client_info *client_info = &dev_info->i2c_client_info[idx]; 736 struct i2c_board_info board_info = client_info->board_info; 737 struct i2c_adapter *adap; 738 acpi_handle handle; 739 acpi_status status; 740 741 board_info.irq = x86_acpi_irq_helper_get(&client_info->irq_data); 742 if (board_info.irq < 0) 743 return board_info.irq; 744 745 status = acpi_get_handle(NULL, client_info->adapter_path, &handle); 746 if (ACPI_FAILURE(status)) { 747 pr_err("Error could not get %s handle\n", client_info->adapter_path); 748 return -ENODEV; 749 } 750 751 adap = i2c_acpi_find_adapter_by_handle(handle); 752 if (!adap) { 753 pr_err("error could not get %s adapter\n", client_info->adapter_path); 754 return -ENODEV; 755 } 756 757 i2c_clients[idx] = i2c_new_client_device(adap, &board_info); 758 put_device(&adap->dev); 759 if (IS_ERR(i2c_clients[idx])) 760 return dev_err_probe(&adap->dev, PTR_ERR(i2c_clients[idx]), 761 "creating I2C-client %d\n", idx); 762 763 return 0; 764} 765 766static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int idx) 767{ 768 struct acpi_device *ctrl_adev, *serdev_adev; 769 struct serdev_device *serdev; 770 struct device *ctrl_dev; 771 int ret = -ENODEV; 772 773 ctrl_adev = acpi_dev_get_first_match_dev(info->ctrl_hid, info->ctrl_uid, -1); 774 if (!ctrl_adev) { 775 pr_err("error could not get %s/%s ctrl adev\n", 776 info->ctrl_hid, info->ctrl_uid); 777 return -ENODEV; 778 } 779 780 serdev_adev = acpi_dev_get_first_match_dev(info->serdev_hid, NULL, -1); 781 if (!serdev_adev) { 782 pr_err("error could not get %s serdev adev\n", info->serdev_hid); 783 goto put_ctrl_adev; 784 } 785 786 /* get_first_physical_node() returns a weak ref, no need to put() it */ 787 ctrl_dev = acpi_get_first_physical_node(ctrl_adev); 788 if (!ctrl_dev) { 789 pr_err("error could not get %s/%s ctrl physical dev\n", 790 info->ctrl_hid, info->ctrl_uid); 791 goto put_serdev_adev; 792 } 793 794 /* ctrl_dev now points to the controller's parent, get the controller */ 795 ctrl_dev = device_find_child_by_name(ctrl_dev, info->ctrl_devname); 796 if (!ctrl_dev) { 797 pr_err("error could not get %s/%s %s ctrl dev\n", 798 info->ctrl_hid, info->ctrl_uid, info->ctrl_devname); 799 goto put_serdev_adev; 800 } 801 802 serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev)); 803 if (!serdev) { 804 ret = -ENOMEM; 805 goto put_serdev_adev; 806 } 807 808 ACPI_COMPANION_SET(&serdev->dev, serdev_adev); 809 acpi_device_set_enumerated(serdev_adev); 810 811 ret = serdev_device_add(serdev); 812 if (ret) { 813 dev_err(&serdev->dev, "error %d adding serdev\n", ret); 814 serdev_device_put(serdev); 815 goto put_serdev_adev; 816 } 817 818 serdevs[idx] = serdev; 819 820put_serdev_adev: 821 acpi_dev_put(serdev_adev); 822put_ctrl_adev: 823 acpi_dev_put(ctrl_adev); 824 return ret; 825} 826 827static void x86_android_tablet_cleanup(void) 828{ 829 int i; 830 831 for (i = 0; i < serdev_count; i++) { 832 if (serdevs[i]) 833 serdev_device_remove(serdevs[i]); 834 } 835 836 kfree(serdevs); 837 838 for (i = 0; i < pdev_count; i++) 839 platform_device_unregister(pdevs[i]); 840 841 kfree(pdevs); 842 843 for (i = 0; i < i2c_client_count; i++) 844 i2c_unregister_device(i2c_clients[i]); 845 846 kfree(i2c_clients); 847 848 if (exit_handler) 849 exit_handler(); 850 851 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) 852 gpiod_remove_lookup_table(gpiod_lookup_tables[i]); 853} 854 855static __init int x86_android_tablet_init(void) 856{ 857 const struct x86_dev_info *dev_info; 858 const struct dmi_system_id *id; 859 struct gpio_chip *chip; 860 int i, ret = 0; 861 862 id = dmi_first_match(x86_android_tablet_ids); 863 if (!id) 864 return -ENODEV; 865 866 dev_info = id->driver_data; 867 868 /* 869 * The broken DSDTs on these devices often also include broken 870 * _AEI (ACPI Event Interrupt) handlers, disable these. 871 */ 872 if (dev_info->invalid_aei_gpiochip) { 873 chip = gpiochip_find(dev_info->invalid_aei_gpiochip, 874 gpiochip_find_match_label); 875 if (!chip) { 876 pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip); 877 return -ENODEV; 878 } 879 acpi_gpiochip_free_interrupts(chip); 880 } 881 882 /* 883 * Since this runs from module_init() it cannot use -EPROBE_DEFER, 884 * instead pre-load any modules which are listed as requirements. 885 */ 886 for (i = 0; dev_info->modules && dev_info->modules[i]; i++) 887 request_module(dev_info->modules[i]); 888 889 gpiod_lookup_tables = dev_info->gpiod_lookup_tables; 890 for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) 891 gpiod_add_lookup_table(gpiod_lookup_tables[i]); 892 893 if (dev_info->init) { 894 ret = dev_info->init(); 895 if (ret < 0) { 896 x86_android_tablet_cleanup(); 897 return ret; 898 } 899 exit_handler = dev_info->exit; 900 } 901 902 i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL); 903 if (!i2c_clients) { 904 x86_android_tablet_cleanup(); 905 return -ENOMEM; 906 } 907 908 i2c_client_count = dev_info->i2c_client_count; 909 for (i = 0; i < i2c_client_count; i++) { 910 ret = x86_instantiate_i2c_client(dev_info, i); 911 if (ret < 0) { 912 x86_android_tablet_cleanup(); 913 return ret; 914 } 915 } 916 917 pdevs = kcalloc(dev_info->pdev_count, sizeof(*pdevs), GFP_KERNEL); 918 if (!pdevs) { 919 x86_android_tablet_cleanup(); 920 return -ENOMEM; 921 } 922 923 pdev_count = dev_info->pdev_count; 924 for (i = 0; i < pdev_count; i++) { 925 pdevs[i] = platform_device_register_full(&dev_info->pdev_info[i]); 926 if (IS_ERR(pdevs[i])) { 927 x86_android_tablet_cleanup(); 928 return PTR_ERR(pdevs[i]); 929 } 930 } 931 932 serdevs = kcalloc(dev_info->serdev_count, sizeof(*serdevs), GFP_KERNEL); 933 if (!serdevs) { 934 x86_android_tablet_cleanup(); 935 return -ENOMEM; 936 } 937 938 serdev_count = dev_info->serdev_count; 939 for (i = 0; i < serdev_count; i++) { 940 ret = x86_instantiate_serdev(&dev_info->serdev_info[i], i); 941 if (ret < 0) { 942 x86_android_tablet_cleanup(); 943 return ret; 944 } 945 } 946 947 return 0; 948} 949 950module_init(x86_android_tablet_init); 951module_exit(x86_android_tablet_cleanup); 952 953MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 954MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver"); 955MODULE_LICENSE("GPL");