xref: /linux/drivers/platform/x86/x86-android-tablets/other.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0-or-later
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-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/pci.h>
16 #include <linux/platform_device.h>
17 #include <linux/pwm.h>
18 
19 #include <dt-bindings/leds/common.h>
20 
21 #include "shared-psy-info.h"
22 #include "x86-android-tablets.h"
23 
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[] = {
26 	"-1", "0", "0",
27 	"0", "1", "0",
28 	"0", "0", "1"
29 };
30 
31 static const struct property_entry acer_b1_750_bma250e_props[] = {
32 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", acer_b1_750_mount_matrix),
33 	{ }
34 };
35 
36 static const struct software_node acer_b1_750_bma250e_node = {
37 	.properties = acer_b1_750_bma250e_props,
38 };
39 
40 static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst = {
41 	{
42 		/* Novatek NVT-ts touchscreen */
43 		.board_info = {
44 			.type = "nt11205-ts",
45 			.addr = 0x34,
46 			.dev_name = "NVT-ts",
47 		},
48 		.adapter_path = "\\_SB_.I2C4",
49 		.irq_data = {
50 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
51 			.chip = "INT33FC:02",
52 			.index = 3,
53 			.trigger = ACPI_EDGE_SENSITIVE,
54 			.polarity = ACPI_ACTIVE_LOW,
55 			.con_id = "NVT-ts_irq",
56 		},
57 	}, {
58 		/* BMA250E accelerometer */
59 		.board_info = {
60 			.type = "bma250e",
61 			.addr = 0x18,
62 			.swnode = &acer_b1_750_bma250e_node,
63 		},
64 		.adapter_path = "\\_SB_.I2C3",
65 		.irq_data = {
66 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
67 			.chip = "INT33FC:02",
68 			.index = 25,
69 			.trigger = ACPI_LEVEL_SENSITIVE,
70 			.polarity = ACPI_ACTIVE_HIGH,
71 			.con_id = "bma250e_irq",
72 		},
73 	},
74 };
75 
76 static struct gpiod_lookup_table acer_b1_750_nvt_ts_gpios = {
77 	.dev_id = "i2c-NVT-ts",
78 	.table = {
79 		GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
80 		{ }
81 	},
82 };
83 
84 static struct gpiod_lookup_table * const acer_b1_750_gpios[] = {
85 	&acer_b1_750_nvt_ts_gpios,
86 	&int3496_reference_gpios,
87 	NULL
88 };
89 
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,
94 	.pdev_count = 1,
95 	.gpiod_lookup_tables = acer_b1_750_gpios,
96 };
97 
98 /*
99  * Advantech MICA-071
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.
103  */
104 static const struct x86_gpio_button advantech_mica_071_button __initconst = {
105 	.button = {
106 		.code = KEY_PROG1,
107 		.active_low = true,
108 		.desc = "prog1_key",
109 		.type = EV_KEY,
110 		.wakeup = false,
111 		.debounce_interval = 50,
112 	},
113 	.chip = "INT33FC:00",
114 	.pin = 2,
115 };
116 
117 const struct x86_dev_info advantech_mica_071_info __initconst = {
118 	.gpio_button = &advantech_mica_071_button,
119 	.gpio_button_count = 1,
120 };
121 
122 /*
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.
126  */
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"),
133 	{ }
134 };
135 
136 static const struct software_node chuwi_hi8_gsl1680_node = {
137 	.properties = chuwi_hi8_gsl1680_props,
138 };
139 
140 static const char * const chuwi_hi8_mount_matrix[] = {
141 	"1", "0", "0",
142 	"0", "-1", "0",
143 	"0", "0", "1"
144 };
145 
146 static const struct property_entry chuwi_hi8_bma250e_props[] = {
147 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
148 	{ }
149 };
150 
151 static const struct software_node chuwi_hi8_bma250e_node = {
152 	.properties = chuwi_hi8_bma250e_props,
153 };
154 
155 static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
156 	{
157 		/* Silead touchscreen */
158 		.board_info = {
159 			.type = "gsl1680",
160 			.addr = 0x40,
161 			.swnode = &chuwi_hi8_gsl1680_node,
162 		},
163 		.adapter_path = "\\_SB_.I2C4",
164 		.irq_data = {
165 			.type = X86_ACPI_IRQ_TYPE_APIC,
166 			.index = 0x44,
167 			.trigger = ACPI_EDGE_SENSITIVE,
168 			.polarity = ACPI_ACTIVE_HIGH,
169 		},
170 	}, {
171 		/* BMA250E accelerometer */
172 		.board_info = {
173 			.type = "bma250e",
174 			.addr = 0x18,
175 			.swnode = &chuwi_hi8_bma250e_node,
176 		},
177 		.adapter_path = "\\_SB_.I2C3",
178 		.irq_data = {
179 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
180 			.chip = "INT33FC:02",
181 			.index = 23,
182 			.trigger = ACPI_LEVEL_SENSITIVE,
183 			.polarity = ACPI_ACTIVE_HIGH,
184 			.con_id = "bma250e_irq",
185 		},
186 	},
187 };
188 
189 static int __init chuwi_hi8_init(struct device *dev)
190 {
191 	/*
192 	 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
193 	 * breaking the touchscreen + logging various errors when the Windows
194 	 * BIOS is used.
195 	 */
196 	if (acpi_dev_present("MSSL0001", NULL, 1))
197 		return -ENODEV;
198 
199 	return 0;
200 }
201 
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,
206 };
207 
208 /*
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.
214  */
215 static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {
216 	{
217 		.button = {
218 			.code = KEY_PROG1,
219 			.active_low = true,
220 			.desc = "prog1_key",
221 			.type = EV_KEY,
222 			.wakeup = false,
223 			.debounce_interval = 50,
224 		},
225 		.chip = "INT33FF:00",
226 		.pin = 30,
227 	},
228 	{
229 		.button = {
230 			.code = KEY_PROG2,
231 			.active_low = true,
232 			.desc = "prog2_key",
233 			.type = EV_KEY,
234 			.wakeup = false,
235 			.debounce_interval = 50,
236 		},
237 		.chip = "INT33FF:03",
238 		.pin = 48,
239 	},
240 };
241 
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),
245 };
246 
247 #define CZC_EC_EXTRA_PORT	0x68
248 #define CZC_EC_ANDROID_KEYS	0x63
249 
250 static int __init czc_p10t_init(struct device *dev)
251 {
252 	/*
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".
257 	 *
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.
264 	 *
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
270 	 * model.
271 	 */
272 	outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
273 	return 0;
274 }
275 
276 const struct x86_dev_info czc_p10t __initconst = {
277 	.init = czc_p10t_init,
278 };
279 
280 /* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */
281 static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
282 	"0", "1", "0",
283 	"1", "0", "0",
284 	"0", "0", "1"
285 };
286 
287 static const struct property_entry medion_lifetab_s10346_accel_props[] = {
288 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
289 	{ }
290 };
291 
292 static const struct software_node medion_lifetab_s10346_accel_node = {
293 	.properties = medion_lifetab_s10346_accel_props,
294 };
295 
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"),
300 	{ }
301 };
302 
303 static const struct software_node medion_lifetab_s10346_touchscreen_node = {
304 	.properties = medion_lifetab_s10346_touchscreen_props,
305 };
306 
307 static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
308 	{
309 		/* kxtj21009 accelerometer */
310 		.board_info = {
311 			.type = "kxtj21009",
312 			.addr = 0x0f,
313 			.dev_name = "kxtj21009",
314 			.swnode = &medion_lifetab_s10346_accel_node,
315 		},
316 		.adapter_path = "\\_SB_.I2C3",
317 		.irq_data = {
318 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
319 			.chip = "INT33FC:02",
320 			.index = 23,
321 			.trigger = ACPI_EDGE_SENSITIVE,
322 			.polarity = ACPI_ACTIVE_HIGH,
323 			.con_id = "kxtj21009_irq",
324 		},
325 	}, {
326 		/* goodix touchscreen */
327 		.board_info = {
328 			.type = "GDIX1001:00",
329 			.addr = 0x14,
330 			.dev_name = "goodix_ts",
331 			.swnode = &medion_lifetab_s10346_touchscreen_node,
332 		},
333 		.adapter_path = "\\_SB_.I2C4",
334 		.irq_data = {
335 			.type = X86_ACPI_IRQ_TYPE_APIC,
336 			.index = 0x44,
337 			.trigger = ACPI_EDGE_SENSITIVE,
338 			.polarity = ACPI_ACTIVE_LOW,
339 		},
340 	},
341 };
342 
343 static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
344 	.dev_id = "i2c-goodix_ts",
345 	.table = {
346 		GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
347 		GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
348 		{ }
349 	},
350 };
351 
352 static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
353 	&medion_lifetab_s10346_goodix_gpios,
354 	NULL
355 };
356 
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,
361 };
362 
363 /* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
364 static const char * const nextbook_ares8_accel_mount_matrix[] = {
365 	"0", "-1", "0",
366 	"-1", "0", "0",
367 	"0", "0", "1"
368 };
369 
370 static const struct property_entry nextbook_ares8_accel_props[] = {
371 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
372 	{ }
373 };
374 
375 static const struct software_node nextbook_ares8_accel_node = {
376 	.properties = nextbook_ares8_accel_props,
377 };
378 
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),
382 	{ }
383 };
384 
385 static const struct software_node nextbook_ares8_touchscreen_node = {
386 	.properties = nextbook_ares8_touchscreen_props,
387 };
388 
389 static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
390 	{
391 		/* Freescale MMA8653FC accelerometer */
392 		.board_info = {
393 			.type = "mma8653",
394 			.addr = 0x1d,
395 			.dev_name = "mma8653",
396 			.swnode = &nextbook_ares8_accel_node,
397 		},
398 		.adapter_path = "\\_SB_.I2C3",
399 	}, {
400 		/* FT5416DQ9 touchscreen controller */
401 		.board_info = {
402 			.type = "edt-ft5x06",
403 			.addr = 0x38,
404 			.dev_name = "ft5416",
405 			.swnode = &nextbook_ares8_touchscreen_node,
406 		},
407 		.adapter_path = "\\_SB_.I2C4",
408 		.irq_data = {
409 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
410 			.chip = "INT33FC:02",
411 			.index = 3,
412 			.trigger = ACPI_EDGE_SENSITIVE,
413 			.polarity = ACPI_ACTIVE_LOW,
414 			.con_id = "ft5416_irq",
415 		},
416 	},
417 };
418 
419 static struct gpiod_lookup_table * const nextbook_ares8_gpios[] = {
420 	&int3496_reference_gpios,
421 	NULL
422 };
423 
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,
428 	.pdev_count = 1,
429 	.gpiod_lookup_tables = nextbook_ares8_gpios,
430 };
431 
432 /* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */
433 static const char * const nextbook_ares8a_accel_mount_matrix[] = {
434 	"1", "0", "0",
435 	"0", "-1", "0",
436 	"0", "0", "1"
437 };
438 
439 static const struct property_entry nextbook_ares8a_accel_props[] = {
440 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),
441 	{ }
442 };
443 
444 static const struct software_node nextbook_ares8a_accel_node = {
445 	.properties = nextbook_ares8a_accel_props,
446 };
447 
448 static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
449 	{
450 		/* Freescale MMA8653FC accelerometer */
451 		.board_info = {
452 			.type = "mma8653",
453 			.addr = 0x1d,
454 			.dev_name = "mma8653",
455 			.swnode = &nextbook_ares8a_accel_node,
456 		},
457 		.adapter_path = "\\_SB_.PCI0.I2C3",
458 	}, {
459 		/* FT5416DQ9 touchscreen controller */
460 		.board_info = {
461 			.type = "edt-ft5x06",
462 			.addr = 0x38,
463 			.dev_name = "ft5416",
464 			.swnode = &nextbook_ares8_touchscreen_node,
465 		},
466 		.adapter_path = "\\_SB_.PCI0.I2C6",
467 		.irq_data = {
468 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
469 			.chip = "INT33FF:01",
470 			.index = 17,
471 			.trigger = ACPI_EDGE_SENSITIVE,
472 			.polarity = ACPI_ACTIVE_LOW,
473 			.con_id = "ft5416_irq",
474 		},
475 	},
476 };
477 
478 static struct gpiod_lookup_table nextbook_ares8a_ft5416_gpios = {
479 	.dev_id = "i2c-ft5416",
480 	.table = {
481 		GPIO_LOOKUP("INT33FF:01", 25, "reset", GPIO_ACTIVE_LOW),
482 		{ }
483 	},
484 };
485 
486 static struct gpiod_lookup_table * const nextbook_ares8a_gpios[] = {
487 	&nextbook_ares8a_ft5416_gpios,
488 	NULL
489 };
490 
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,
495 };
496 
497 /*
498  * Peaq C1010
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.
502  */
503 static const struct x86_gpio_button peaq_c1010_button __initconst = {
504 	.button = {
505 		.code = KEY_SOUND,
506 		.active_low = true,
507 		.desc = "dolby_key",
508 		.type = EV_KEY,
509 		.wakeup = false,
510 		.debounce_interval = 50,
511 	},
512 	.chip = "INT33FC:00",
513 	.pin = 3,
514 };
515 
516 const struct x86_dev_info peaq_c1010_info __initconst = {
517 	.gpio_button = &peaq_c1010_button,
518 	.gpio_button_count = 1,
519 };
520 
521 /*
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.
526  */
527 static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
528 	"-1", "0", "0",
529 	"0", "1", "0",
530 	"0", "0", "1"
531 };
532 
533 static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
534 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
535 	{ }
536 };
537 
538 static const struct software_node whitelabel_tm800a550l_accel_node = {
539 	.properties = whitelabel_tm800a550l_accel_props,
540 };
541 
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),
546 	{ }
547 };
548 
549 static const struct software_node whitelabel_tm800a550l_goodix_node = {
550 	.properties = whitelabel_tm800a550l_goodix_props,
551 };
552 
553 static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
554 	{
555 		/* goodix touchscreen */
556 		.board_info = {
557 			.type = "GDIX1001:00",
558 			.addr = 0x14,
559 			.dev_name = "goodix_ts",
560 			.swnode = &whitelabel_tm800a550l_goodix_node,
561 		},
562 		.adapter_path = "\\_SB_.I2C2",
563 		.irq_data = {
564 			.type = X86_ACPI_IRQ_TYPE_APIC,
565 			.index = 0x44,
566 			.trigger = ACPI_EDGE_SENSITIVE,
567 			.polarity = ACPI_ACTIVE_HIGH,
568 		},
569 	}, {
570 		/* kxcj91008 accelerometer */
571 		.board_info = {
572 			.type = "kxcj91008",
573 			.addr = 0x0f,
574 			.dev_name = "kxcj91008",
575 			.swnode = &whitelabel_tm800a550l_accel_node,
576 		},
577 		.adapter_path = "\\_SB_.I2C3",
578 	},
579 };
580 
581 static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
582 	.dev_id = "i2c-goodix_ts",
583 	.table = {
584 		GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
585 		GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
586 		{ }
587 	},
588 };
589 
590 static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
591 	&whitelabel_tm800a550l_goodix_gpios,
592 	NULL
593 };
594 
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,
599 };
600 
601 /*
602  * Vexia EDU ATLA 10 tablet, Android 4.2 / 4.4 + Guadalinex Ubuntu tablet
603  * distributed to schools in the Spanish Andalucía region.
604  */
605 const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
606 
607 static const struct property_entry vexia_edu_atla10_ulpmc_props[] = {
608 	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
609 	{ }
610 };
611 
612 const struct software_node vexia_edu_atla10_ulpmc_node = {
613 	.properties = vexia_edu_atla10_ulpmc_props,
614 };
615 
616 static const char * const vexia_edu_atla10_accel_mount_matrix[] = {
617 	"0", "-1", "0",
618 	"1", "0", "0",
619 	"0", "0", "1"
620 };
621 
622 static const struct property_entry vexia_edu_atla10_accel_props[] = {
623 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_accel_mount_matrix),
624 	{ }
625 };
626 
627 static const struct software_node vexia_edu_atla10_accel_node = {
628 	.properties = vexia_edu_atla10_accel_props,
629 };
630 
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),
634 	{ }
635 };
636 
637 static const struct software_node vexia_edu_atla10_touchscreen_node = {
638 	.properties = vexia_edu_atla10_touchscreen_props,
639 };
640 
641 static const struct property_entry vexia_edu_atla10_pmic_props[] = {
642 	PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
643 	{ }
644 };
645 
646 static const struct software_node vexia_edu_atla10_pmic_node = {
647 	.properties = vexia_edu_atla10_pmic_props,
648 };
649 
650 static const struct x86_i2c_client_info vexia_edu_atla10_i2c_clients[] __initconst = {
651 	{
652 		/* I2C attached embedded controller, used to access fuel-gauge */
653 		.board_info = {
654 			.type = "vexia_atla10_ec",
655 			.addr = 0x76,
656 			.dev_name = "ulpmc",
657 			.swnode = &vexia_edu_atla10_ulpmc_node,
658 		},
659 		.adapter_path = "0000:00:18.1",
660 	}, {
661 		/* RT5642 audio codec */
662 		.board_info = {
663 			.type = "rt5640",
664 			.addr = 0x1c,
665 			.dev_name = "rt5640",
666 		},
667 		.adapter_path = "0000:00:18.2",
668 		.irq_data = {
669 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
670 			.chip = "INT33FC:02",
671 			.index = 4,
672 			.trigger = ACPI_EDGE_SENSITIVE,
673 			.polarity = ACPI_ACTIVE_HIGH,
674 			.con_id = "rt5640_irq",
675 		},
676 	}, {
677 		/* kxtj21009 accelerometer */
678 		.board_info = {
679 			.type = "kxtj21009",
680 			.addr = 0x0f,
681 			.dev_name = "kxtj21009",
682 			.swnode = &vexia_edu_atla10_accel_node,
683 		},
684 		.adapter_path = "0000:00:18.5",
685 	}, {
686 		/* FT5416DQ9 touchscreen controller */
687 		.board_info = {
688 			.type = "hid-over-i2c",
689 			.addr = 0x38,
690 			.dev_name = "FTSC1000",
691 			.swnode = &vexia_edu_atla10_touchscreen_node,
692 		},
693 		.adapter_path = "0000:00:18.6",
694 		.irq_data = {
695 			.type = X86_ACPI_IRQ_TYPE_APIC,
696 			.index = 0x45,
697 			.trigger = ACPI_LEVEL_SENSITIVE,
698 			.polarity = ACPI_ACTIVE_HIGH,
699 		},
700 	}, {
701 		/* Crystal Cove PMIC */
702 		.board_info = {
703 			.type = "intel_soc_pmic_crc",
704 			.addr = 0x6e,
705 			.dev_name = "intel_soc_pmic_crc",
706 			.swnode = &vexia_edu_atla10_pmic_node,
707 		},
708 		.adapter_path = "0000:00:18.7",
709 		.irq_data = {
710 			.type = X86_ACPI_IRQ_TYPE_APIC,
711 			.index = 0x43,
712 			.trigger = ACPI_LEVEL_SENSITIVE,
713 			.polarity = ACPI_ACTIVE_HIGH,
714 		},
715 	}
716 };
717 
718 static struct gpiod_lookup_table vexia_edu_atla10_ft5416_gpios = {
719 	.dev_id = "i2c-FTSC1000",
720 	.table = {
721 		GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW),
722 		{ }
723 	},
724 };
725 
726 static struct gpiod_lookup_table * const vexia_edu_atla10_gpios[] = {
727 	&vexia_edu_atla10_ft5416_gpios,
728 	NULL
729 };
730 
731 static int __init vexia_edu_atla10_init(struct device *dev)
732 {
733 	struct pci_dev *pdev;
734 	int ret;
735 
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);
739 	if (ret)
740 		return ret;
741 
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));
744 	if (!pdev)
745 		return -EPROBE_DEFER;
746 
747 	ret = device_reprobe(&pdev->dev);
748 	if (ret)
749 		pci_warn(pdev, "Reprobing error: %d\n", ret);
750 
751 	pci_dev_put(pdev);
752 	return 0;
753 }
754 
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,
761 };
762 
763 /*
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.
767  */
768 
769 /* Main firmware node for ktd2026 */
770 static const struct software_node ktd2026_node = {
771 	.name = "ktd2026",
772 };
773 
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"),
779 	{ }
780 };
781 
782 static const struct software_node ktd2026_rgb_led_node = {
783 	.name = "multi-led",
784 	.properties = ktd2026_rgb_led_props,
785 	.parent = &ktd2026_node,
786 };
787 
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),
791 	{ }
792 };
793 
794 static const struct software_node ktd2026_blue_led_node = {
795 	.properties = ktd2026_blue_led_props,
796 	.parent = &ktd2026_rgb_led_node,
797 };
798 
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),
802 	{ }
803 };
804 
805 static const struct software_node ktd2026_green_led_node = {
806 	.properties = ktd2026_green_led_props,
807 	.parent = &ktd2026_rgb_led_node,
808 };
809 
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),
813 	{ }
814 };
815 
816 static const struct software_node ktd2026_red_led_node = {
817 	.properties = ktd2026_red_led_props,
818 	.parent = &ktd2026_rgb_led_node,
819 };
820 
821 static const struct software_node *ktd2026_node_group[] = {
822 	&ktd2026_node,
823 	&ktd2026_rgb_led_node,
824 	&ktd2026_red_led_node,
825 	&ktd2026_green_led_node,
826 	&ktd2026_blue_led_node,
827 	NULL
828 };
829 
830 /*
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.
834  */
835 #define XIAOMI_MIPAD2_LED_PERIOD_NS		19200
836 #define XIAOMI_MIPAD2_LED_MAX_DUTY_NS		 6000 /* From Android kernel */
837 
838 static struct pwm_device *xiaomi_mipad2_led_pwm;
839 
840 static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
841 					enum led_brightness val)
842 {
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 */
847 		.enabled = true,
848 	};
849 
850 	return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
851 }
852 
853 static int __init xiaomi_mipad2_init(struct device *dev)
854 {
855 	struct led_classdev *led_cdev;
856 	int ret;
857 
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");
861 
862 	led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
863 	if (!led_cdev)
864 		return -ENOMEM;
865 
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;
872 
873 	ret = devm_led_classdev_register(dev, led_cdev);
874 	if (ret)
875 		return dev_err_probe(dev, ret, "registering LED\n");
876 
877 	return software_node_register_node_group(ktd2026_node_group);
878 }
879 
880 static void xiaomi_mipad2_exit(void)
881 {
882 	software_node_unregister_node_group(ktd2026_node_group);
883 }
884 
885 /*
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.
889  *
890  * This takes care of instantiating the hidden devices manually.
891  */
892 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
893 	{
894 		/* BQ27520 fuel-gauge */
895 		.board_info = {
896 			.type = "bq27520",
897 			.addr = 0x55,
898 			.dev_name = "bq27520",
899 			.swnode = &fg_bq25890_supply_node,
900 		},
901 		.adapter_path = "\\_SB_.PCI0.I2C1",
902 	}, {
903 		/* KTD2026 RGB notification LED controller */
904 		.board_info = {
905 			.type = "ktd2026",
906 			.addr = 0x30,
907 			.dev_name = "ktd2026",
908 			.swnode = &ktd2026_node,
909 		},
910 		.adapter_path = "\\_SB_.PCI0.I2C3",
911 	},
912 };
913 
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,
919 };
920