Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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");