xref: /linux/drivers/platform/x86/x86-android-tablets/other.c (revision 6093a688a07da07808f0122f9aa2a3eed250d853)
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 <hansg@kernel.org>
9  */
10 
11 #include <linux/acpi.h>
12 #include <linux/gpio/machine.h>
13 #include <linux/gpio/property.h>
14 #include <linux/input-event-codes.h>
15 #include <linux/leds.h>
16 #include <linux/pci.h>
17 #include <linux/platform_device.h>
18 #include <linux/pwm.h>
19 
20 #include <dt-bindings/leds/common.h>
21 
22 #include "shared-psy-info.h"
23 #include "x86-android-tablets.h"
24 
25 /*
26  * Advantech MICA-071
27  * This is a standard Windows tablet, but it has an extra "quick launch" button
28  * which is not described in the ACPI tables in anyway.
29  * Use the x86-android-tablets infra to create a gpio-keys device for this.
30  */
31 static const struct software_node advantech_mica_071_gpio_keys_node = {
32 	.name = "prog1_key",
33 };
34 
35 static const struct property_entry advantech_mica_071_prog1_key_props[] = {
36 	PROPERTY_ENTRY_U32("linux,code", KEY_PROG1),
37 	PROPERTY_ENTRY_STRING("label", "prog1_key"),
38 	PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[0], 2, GPIO_ACTIVE_LOW),
39 	PROPERTY_ENTRY_U32("debounce-interval", 50),
40 	{ }
41 };
42 
43 static const struct software_node advantech_mica_071_prog1_key_node = {
44 	.parent = &advantech_mica_071_gpio_keys_node,
45 	.properties = advantech_mica_071_prog1_key_props,
46 };
47 
48 static const struct software_node *advantech_mica_071_button_swnodes[] = {
49 	&advantech_mica_071_gpio_keys_node,
50 	&advantech_mica_071_prog1_key_node,
51 	NULL
52 };
53 
54 const struct x86_dev_info advantech_mica_071_info __initconst = {
55 	.gpio_button_swnodes = advantech_mica_071_button_swnodes,
56 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
57 };
58 
59 /*
60  * When booted with the BIOS set to Android mode the Chuwi Hi8 (CWI509) DSDT
61  * contains a whole bunch of bogus ACPI I2C devices and is missing entries
62  * for the touchscreen and the accelerometer.
63  */
64 static const struct property_entry chuwi_hi8_gsl1680_props[] = {
65 	PROPERTY_ENTRY_U32("touchscreen-size-x", 1665),
66 	PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
67 	PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
68 	PROPERTY_ENTRY_BOOL("silead,home-button"),
69 	PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"),
70 	{ }
71 };
72 
73 static const struct software_node chuwi_hi8_gsl1680_node = {
74 	.properties = chuwi_hi8_gsl1680_props,
75 };
76 
77 static const char * const chuwi_hi8_mount_matrix[] = {
78 	"1", "0", "0",
79 	"0", "-1", "0",
80 	"0", "0", "1"
81 };
82 
83 static const struct property_entry chuwi_hi8_bma250e_props[] = {
84 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", chuwi_hi8_mount_matrix),
85 	{ }
86 };
87 
88 static const struct software_node chuwi_hi8_bma250e_node = {
89 	.properties = chuwi_hi8_bma250e_props,
90 };
91 
92 static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
93 	{
94 		/* Silead touchscreen */
95 		.board_info = {
96 			.type = "gsl1680",
97 			.addr = 0x40,
98 			.swnode = &chuwi_hi8_gsl1680_node,
99 		},
100 		.adapter_path = "\\_SB_.I2C4",
101 		.irq_data = {
102 			.type = X86_ACPI_IRQ_TYPE_APIC,
103 			.index = 0x44,
104 			.trigger = ACPI_EDGE_SENSITIVE,
105 			.polarity = ACPI_ACTIVE_HIGH,
106 		},
107 	}, {
108 		/* BMA250E accelerometer */
109 		.board_info = {
110 			.type = "bma250e",
111 			.addr = 0x18,
112 			.swnode = &chuwi_hi8_bma250e_node,
113 		},
114 		.adapter_path = "\\_SB_.I2C3",
115 		.irq_data = {
116 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
117 			.chip = "INT33FC:02",
118 			.index = 23,
119 			.trigger = ACPI_LEVEL_SENSITIVE,
120 			.polarity = ACPI_ACTIVE_HIGH,
121 			.con_id = "bma250e_irq",
122 		},
123 	},
124 };
125 
126 static int __init chuwi_hi8_init(struct device *dev)
127 {
128 	/*
129 	 * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get()
130 	 * breaking the touchscreen + logging various errors when the Windows
131 	 * BIOS is used.
132 	 */
133 	if (acpi_dev_present("MSSL0001", NULL, 1))
134 		return -ENODEV;
135 
136 	return 0;
137 }
138 
139 const struct x86_dev_info chuwi_hi8_info __initconst = {
140 	.i2c_client_info = chuwi_hi8_i2c_clients,
141 	.i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
142 	.init = chuwi_hi8_init,
143 };
144 
145 /*
146  * Cyberbook T116 Android version
147  * This comes in both Windows and Android versions and even on Android
148  * the DSDT is mostly sane. This tablet has 2 extra general purpose buttons
149  * in the button row with the power + volume-buttons labeled P and F.
150  * Use the x86-android-tablets infra to create a gpio-keys device for these.
151  */
152 static const struct software_node cyberbook_t116_gpio_keys_node = {
153 	.name = "prog_keys",
154 };
155 
156 static const struct property_entry cyberbook_t116_prog1_key_props[] = {
157 	PROPERTY_ENTRY_U32("linux,code", KEY_PROG1),
158 	PROPERTY_ENTRY_STRING("label", "prog1_key"),
159 	PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[0], 30, GPIO_ACTIVE_LOW),
160 	PROPERTY_ENTRY_U32("debounce-interval", 50),
161 	{ }
162 };
163 
164 static const struct software_node cyberbook_t116_prog1_key_node = {
165 	.parent = &cyberbook_t116_gpio_keys_node,
166 	.properties = cyberbook_t116_prog1_key_props,
167 };
168 
169 static const struct property_entry cyberbook_t116_prog2_key_props[] = {
170 	PROPERTY_ENTRY_U32("linux,code", KEY_PROG2),
171 	PROPERTY_ENTRY_STRING("label", "prog2_key"),
172 	PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[3], 48, GPIO_ACTIVE_LOW),
173 	PROPERTY_ENTRY_U32("debounce-interval", 50),
174 	{ }
175 };
176 
177 static const struct software_node cyberbook_t116_prog2_key_node = {
178 	.parent = &cyberbook_t116_gpio_keys_node,
179 	.properties = cyberbook_t116_prog2_key_props,
180 };
181 
182 static const struct software_node *cyberbook_t116_buttons_swnodes[] = {
183 	&cyberbook_t116_gpio_keys_node,
184 	&cyberbook_t116_prog1_key_node,
185 	&cyberbook_t116_prog2_key_node,
186 	NULL
187 };
188 
189 const struct x86_dev_info cyberbook_t116_info __initconst = {
190 	.gpio_button_swnodes = cyberbook_t116_buttons_swnodes,
191 	.gpiochip_type = X86_GPIOCHIP_CHERRYVIEW,
192 };
193 
194 #define CZC_EC_EXTRA_PORT	0x68
195 #define CZC_EC_ANDROID_KEYS	0x63
196 
197 static int __init czc_p10t_init(struct device *dev)
198 {
199 	/*
200 	 * The device boots up in "Windows 7" mode, when the home button sends a
201 	 * Windows specific key sequence (Left Meta + D) and the second button
202 	 * sends an unknown one while also toggling the Radio Kill Switch.
203 	 * This is a surprising behavior when the second button is labeled "Back".
204 	 *
205 	 * The vendor-supplied Android-x86 build switches the device to a "Android"
206 	 * mode by writing value 0x63 to the I/O port 0x68. This just seems to just
207 	 * set bit 6 on address 0x96 in the EC region; switching the bit directly
208 	 * seems to achieve the same result. It uses a "p10t_switcher" to do the
209 	 * job. It doesn't seem to be able to do anything else, and no other use
210 	 * of the port 0x68 is known.
211 	 *
212 	 * In the Android mode, the home button sends just a single scancode,
213 	 * which can be handled in Linux userspace more reasonably and the back
214 	 * button only sends a scancode without toggling the kill switch.
215 	 * The scancode can then be mapped either to Back or RF Kill functionality
216 	 * in userspace, depending on how the button is labeled on that particular
217 	 * model.
218 	 */
219 	outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
220 	return 0;
221 }
222 
223 const struct x86_dev_info czc_p10t __initconst = {
224 	.init = czc_p10t_init,
225 };
226 
227 /* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */
228 static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
229 	"0", "1", "0",
230 	"1", "0", "0",
231 	"0", "0", "1"
232 };
233 
234 static const struct property_entry medion_lifetab_s10346_accel_props[] = {
235 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
236 	{ }
237 };
238 
239 static const struct software_node medion_lifetab_s10346_accel_node = {
240 	.properties = medion_lifetab_s10346_accel_props,
241 };
242 
243 /* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
244 static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
245 	PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
246 	PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
247 	PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH),
248 	PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH),
249 	{ }
250 };
251 
252 static const struct software_node medion_lifetab_s10346_touchscreen_node = {
253 	.properties = medion_lifetab_s10346_touchscreen_props,
254 };
255 
256 static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
257 	{
258 		/* kxtj21009 accelerometer */
259 		.board_info = {
260 			.type = "kxtj21009",
261 			.addr = 0x0f,
262 			.dev_name = "kxtj21009",
263 			.swnode = &medion_lifetab_s10346_accel_node,
264 		},
265 		.adapter_path = "\\_SB_.I2C3",
266 		.irq_data = {
267 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
268 			.chip = "INT33FC:02",
269 			.index = 23,
270 			.trigger = ACPI_EDGE_SENSITIVE,
271 			.polarity = ACPI_ACTIVE_HIGH,
272 			.con_id = "kxtj21009_irq",
273 		},
274 	}, {
275 		/* goodix touchscreen */
276 		.board_info = {
277 			.type = "GDIX1001:00",
278 			.addr = 0x14,
279 			.dev_name = "goodix_ts",
280 			.swnode = &medion_lifetab_s10346_touchscreen_node,
281 		},
282 		.adapter_path = "\\_SB_.I2C4",
283 		.irq_data = {
284 			.type = X86_ACPI_IRQ_TYPE_APIC,
285 			.index = 0x44,
286 			.trigger = ACPI_EDGE_SENSITIVE,
287 			.polarity = ACPI_ACTIVE_LOW,
288 		},
289 	},
290 };
291 
292 const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
293 	.i2c_client_info = medion_lifetab_s10346_i2c_clients,
294 	.i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
295 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
296 };
297 
298 /* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
299 static const char * const nextbook_ares8_accel_mount_matrix[] = {
300 	"0", "-1", "0",
301 	"-1", "0", "0",
302 	"0", "0", "1"
303 };
304 
305 static const struct property_entry nextbook_ares8_accel_props[] = {
306 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8_accel_mount_matrix),
307 	{ }
308 };
309 
310 static const struct software_node nextbook_ares8_accel_node = {
311 	.properties = nextbook_ares8_accel_props,
312 };
313 
314 static const struct property_entry nextbook_ares8_touchscreen_props[] = {
315 	PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
316 	PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
317 	{ }
318 };
319 
320 static const struct software_node nextbook_ares8_touchscreen_node = {
321 	.properties = nextbook_ares8_touchscreen_props,
322 };
323 
324 static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
325 	{
326 		/* Freescale MMA8653FC accelerometer */
327 		.board_info = {
328 			.type = "mma8653",
329 			.addr = 0x1d,
330 			.dev_name = "mma8653",
331 			.swnode = &nextbook_ares8_accel_node,
332 		},
333 		.adapter_path = "\\_SB_.I2C3",
334 	}, {
335 		/* FT5416DQ9 touchscreen controller */
336 		.board_info = {
337 			.type = "edt-ft5x06",
338 			.addr = 0x38,
339 			.dev_name = "ft5416",
340 			.swnode = &nextbook_ares8_touchscreen_node,
341 		},
342 		.adapter_path = "\\_SB_.I2C4",
343 		.irq_data = {
344 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
345 			.chip = "INT33FC:02",
346 			.index = 3,
347 			.trigger = ACPI_EDGE_SENSITIVE,
348 			.polarity = ACPI_ACTIVE_LOW,
349 			.con_id = "ft5416_irq",
350 		},
351 	},
352 };
353 
354 const struct x86_dev_info nextbook_ares8_info __initconst = {
355 	.i2c_client_info = nextbook_ares8_i2c_clients,
356 	.i2c_client_count = ARRAY_SIZE(nextbook_ares8_i2c_clients),
357 	.pdev_info = int3496_pdevs,
358 	.pdev_count = 1,
359 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
360 };
361 
362 /* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */
363 static const char * const nextbook_ares8a_accel_mount_matrix[] = {
364 	"1", "0", "0",
365 	"0", "-1", "0",
366 	"0", "0", "1"
367 };
368 
369 static const struct property_entry nextbook_ares8a_accel_props[] = {
370 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", nextbook_ares8a_accel_mount_matrix),
371 	{ }
372 };
373 
374 static const struct software_node nextbook_ares8a_accel_node = {
375 	.properties = nextbook_ares8a_accel_props,
376 };
377 
378 static const struct property_entry nextbook_ares8a_ft5416_props[] = {
379 	PROPERTY_ENTRY_U32("touchscreen-size-x", 800),
380 	PROPERTY_ENTRY_U32("touchscreen-size-y", 1280),
381 	PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[1], 25, GPIO_ACTIVE_LOW),
382 	{ }
383 };
384 
385 static const struct software_node nextbook_ares8a_ft5416_node = {
386 	.properties = nextbook_ares8a_ft5416_props,
387 };
388 
389 static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
390 	{
391 		/* Freescale MMA8653FC accelerometer */
392 		.board_info = {
393 			.type = "mma8653",
394 			.addr = 0x1d,
395 			.dev_name = "mma8653",
396 			.swnode = &nextbook_ares8a_accel_node,
397 		},
398 		.adapter_path = "\\_SB_.PCI0.I2C3",
399 	}, {
400 		/* FT5416DQ9 touchscreen controller */
401 		.board_info = {
402 			.type = "edt-ft5x06",
403 			.addr = 0x38,
404 			.dev_name = "ft5416",
405 			.swnode = &nextbook_ares8a_ft5416_node,
406 		},
407 		.adapter_path = "\\_SB_.PCI0.I2C6",
408 		.irq_data = {
409 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
410 			.chip = "INT33FF:01",
411 			.index = 17,
412 			.trigger = ACPI_EDGE_SENSITIVE,
413 			.polarity = ACPI_ACTIVE_LOW,
414 			.con_id = "ft5416_irq",
415 		},
416 	},
417 };
418 
419 const struct x86_dev_info nextbook_ares8a_info __initconst = {
420 	.i2c_client_info = nextbook_ares8a_i2c_clients,
421 	.i2c_client_count = ARRAY_SIZE(nextbook_ares8a_i2c_clients),
422 	.gpiochip_type = X86_GPIOCHIP_CHERRYVIEW,
423 };
424 
425 /*
426  * Peaq C1010
427  * This is a standard Windows tablet, but it has a special Dolby button.
428  * This button has a WMI interface, but that is broken. Instead of trying to
429  * use the broken WMI interface, instantiate a gpio-keys device for this.
430  */
431 static const struct software_node peaq_c1010_gpio_keys_node = {
432 	.name = "gpio_keys",
433 };
434 
435 static const struct property_entry peaq_c1010_dolby_key_props[] = {
436 	PROPERTY_ENTRY_U32("linux,code", KEY_SOUND),
437 	PROPERTY_ENTRY_STRING("label", "dolby_key"),
438 	PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[0], 3, GPIO_ACTIVE_LOW),
439 	PROPERTY_ENTRY_U32("debounce-interval", 50),
440 	{ }
441 };
442 
443 static const struct software_node peaq_c1010_dolby_key_node = {
444 	.parent = &peaq_c1010_gpio_keys_node,
445 	.properties = peaq_c1010_dolby_key_props,
446 };
447 
448 static const struct software_node *peaq_c1010_button_swnodes[] = {
449 	&peaq_c1010_gpio_keys_node,
450 	&peaq_c1010_dolby_key_node,
451 	NULL
452 };
453 
454 const struct x86_dev_info peaq_c1010_info __initconst = {
455 	.gpio_button_swnodes = peaq_c1010_button_swnodes,
456 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
457 };
458 
459 /*
460  * Whitelabel (sold as various brands) TM800A550L tablets.
461  * These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
462  * (removed through acpi_quirk_skip_i2c_client_enumeration()) and
463  * the touchscreen firmware node has the wrong GPIOs.
464  */
465 static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
466 	"-1", "0", "0",
467 	"0", "1", "0",
468 	"0", "0", "1"
469 };
470 
471 static const struct property_entry whitelabel_tm800a550l_accel_props[] = {
472 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", whitelabel_tm800a550l_accel_mount_matrix),
473 	{ }
474 };
475 
476 static const struct software_node whitelabel_tm800a550l_accel_node = {
477 	.properties = whitelabel_tm800a550l_accel_props,
478 };
479 
480 static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
481 	PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
482 	PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
483 	PROPERTY_ENTRY_U32("goodix,main-clk", 54),
484 	PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH),
485 	PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH),
486 	{ }
487 };
488 
489 static const struct software_node whitelabel_tm800a550l_goodix_node = {
490 	.properties = whitelabel_tm800a550l_goodix_props,
491 };
492 
493 static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __initconst = {
494 	{
495 		/* goodix touchscreen */
496 		.board_info = {
497 			.type = "GDIX1001:00",
498 			.addr = 0x14,
499 			.dev_name = "goodix_ts",
500 			.swnode = &whitelabel_tm800a550l_goodix_node,
501 		},
502 		.adapter_path = "\\_SB_.I2C2",
503 		.irq_data = {
504 			.type = X86_ACPI_IRQ_TYPE_APIC,
505 			.index = 0x44,
506 			.trigger = ACPI_EDGE_SENSITIVE,
507 			.polarity = ACPI_ACTIVE_HIGH,
508 		},
509 	}, {
510 		/* kxcj91008 accelerometer */
511 		.board_info = {
512 			.type = "kxcj91008",
513 			.addr = 0x0f,
514 			.dev_name = "kxcj91008",
515 			.swnode = &whitelabel_tm800a550l_accel_node,
516 		},
517 		.adapter_path = "\\_SB_.I2C3",
518 	},
519 };
520 
521 const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
522 	.i2c_client_info = whitelabel_tm800a550l_i2c_clients,
523 	.i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
524 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
525 };
526 
527 /*
528  * Vexia EDU ATLA 10 tablet 5V, Android 4.4 + Guadalinex Ubuntu tablet
529  * distributed to schools in the Spanish Andalucía region.
530  */
531 static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = {
532 	PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
533 	PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
534 	PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_LOW),
535 	{ }
536 };
537 
538 static const struct software_node vexia_edu_atla10_5v_touchscreen_node = {
539 	.properties = vexia_edu_atla10_5v_touchscreen_props,
540 };
541 
542 static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __initconst = {
543 	{
544 		/* kxcjk1013 accelerometer */
545 		.board_info = {
546 			.type = "kxcjk1013",
547 			.addr = 0x0f,
548 			.dev_name = "kxcjk1013",
549 		},
550 		.adapter_path = "\\_SB_.I2C3",
551 	}, {
552 		/*  touchscreen controller */
553 		.board_info = {
554 			.type = "hid-over-i2c",
555 			.addr = 0x38,
556 			.dev_name = "FTSC1000",
557 			.swnode = &vexia_edu_atla10_5v_touchscreen_node,
558 		},
559 		.adapter_path = "\\_SB_.I2C4",
560 		.irq_data = {
561 			.type = X86_ACPI_IRQ_TYPE_APIC,
562 			.index = 0x44,
563 			.trigger = ACPI_LEVEL_SENSITIVE,
564 			.polarity = ACPI_ACTIVE_HIGH,
565 		},
566 	}
567 };
568 
569 const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = {
570 	.i2c_client_info = vexia_edu_atla10_5v_i2c_clients,
571 	.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients),
572 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
573 };
574 
575 /*
576  * Vexia EDU ATLA 10 tablet 9V, Android 4.2 + Guadalinex Ubuntu tablet
577  * distributed to schools in the Spanish Andalucía region.
578  */
579 static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
580 
581 static const struct property_entry vexia_edu_atla10_9v_ulpmc_props[] = {
582 	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
583 	{ }
584 };
585 
586 static const struct software_node vexia_edu_atla10_9v_ulpmc_node = {
587 	.properties = vexia_edu_atla10_9v_ulpmc_props,
588 };
589 
590 static const char * const vexia_edu_atla10_9v_accel_mount_matrix[] = {
591 	"0", "-1", "0",
592 	"1", "0", "0",
593 	"0", "0", "1"
594 };
595 
596 static const struct property_entry vexia_edu_atla10_9v_accel_props[] = {
597 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_9v_accel_mount_matrix),
598 	{ }
599 };
600 
601 static const struct software_node vexia_edu_atla10_9v_accel_node = {
602 	.properties = vexia_edu_atla10_9v_accel_props,
603 };
604 
605 static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = {
606 	PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
607 	PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
608 	PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[0], 60, GPIO_ACTIVE_LOW),
609 	{ }
610 };
611 
612 static const struct software_node vexia_edu_atla10_9v_touchscreen_node = {
613 	.properties = vexia_edu_atla10_9v_touchscreen_props,
614 };
615 
616 static const struct property_entry vexia_edu_atla10_9v_pmic_props[] = {
617 	PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
618 	{ }
619 };
620 
621 static const struct software_node vexia_edu_atla10_9v_pmic_node = {
622 	.properties = vexia_edu_atla10_9v_pmic_props,
623 };
624 
625 static const struct x86_i2c_client_info vexia_edu_atla10_9v_i2c_clients[] __initconst = {
626 	{
627 		/* I2C attached embedded controller, used to access fuel-gauge */
628 		.board_info = {
629 			.type = "vexia_atla10_ec",
630 			.addr = 0x76,
631 			.dev_name = "ulpmc",
632 			.swnode = &vexia_edu_atla10_9v_ulpmc_node,
633 		},
634 		.adapter_path = "0000:00:18.1",
635 	}, {
636 		/* RT5642 audio codec */
637 		.board_info = {
638 			.type = "rt5640",
639 			.addr = 0x1c,
640 			.dev_name = "rt5640",
641 		},
642 		.adapter_path = "0000:00:18.2",
643 		.irq_data = {
644 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
645 			.chip = "INT33FC:02",
646 			.index = 4,
647 			.trigger = ACPI_EDGE_SENSITIVE,
648 			.polarity = ACPI_ACTIVE_HIGH,
649 			.con_id = "rt5640_irq",
650 		},
651 	}, {
652 		/* kxtj21009 accelerometer */
653 		.board_info = {
654 			.type = "kxtj21009",
655 			.addr = 0x0f,
656 			.dev_name = "kxtj21009",
657 			.swnode = &vexia_edu_atla10_9v_accel_node,
658 		},
659 		.adapter_path = "0000:00:18.5",
660 	}, {
661 		/* FT5416DQ9 touchscreen controller */
662 		.board_info = {
663 			.type = "hid-over-i2c",
664 			.addr = 0x38,
665 			.dev_name = "FTSC1000",
666 			.swnode = &vexia_edu_atla10_9v_touchscreen_node,
667 		},
668 		.adapter_path = "0000:00:18.6",
669 		.irq_data = {
670 			.type = X86_ACPI_IRQ_TYPE_APIC,
671 			.index = 0x45,
672 			.trigger = ACPI_LEVEL_SENSITIVE,
673 			.polarity = ACPI_ACTIVE_HIGH,
674 		},
675 	}, {
676 		/* Crystal Cove PMIC */
677 		.board_info = {
678 			.type = "intel_soc_pmic_crc",
679 			.addr = 0x6e,
680 			.dev_name = "intel_soc_pmic_crc",
681 			.swnode = &vexia_edu_atla10_9v_pmic_node,
682 		},
683 		.adapter_path = "0000:00:18.7",
684 		.irq_data = {
685 			.type = X86_ACPI_IRQ_TYPE_APIC,
686 			.index = 0x43,
687 			.trigger = ACPI_LEVEL_SENSITIVE,
688 			.polarity = ACPI_ACTIVE_HIGH,
689 		},
690 	}
691 };
692 
693 static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = {
694 	{
695 		.ctrl.pci.devfn = PCI_DEVFN(0x1e, 3),
696 		.ctrl_devname = "serial0",
697 		.serdev_hid = "OBDA8723",
698 	},
699 };
700 
701 static int __init vexia_edu_atla10_9v_init(struct device *dev)
702 {
703 	struct pci_dev *pdev;
704 	int ret;
705 
706 	/* Enable the Wifi module by setting the wifi_enable pin to 1 */
707 	ret = x86_android_tablet_get_gpiod("INT33FC:02", 20, "wifi_enable",
708 					   false, GPIOD_OUT_HIGH, NULL);
709 	if (ret)
710 		return ret;
711 
712 	/* Reprobe the SDIO controller to enumerate the now enabled Wifi module */
713 	pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x11, 0));
714 	if (!pdev) {
715 		pr_warn("Could not get PCI SDIO at devfn 0x%02x\n", PCI_DEVFN(0x11, 0));
716 		return 0;
717 	}
718 
719 	ret = device_reprobe(&pdev->dev);
720 	if (ret)
721 		pci_warn(pdev, "Reprobing error: %d\n", ret);
722 
723 	pci_dev_put(pdev);
724 	return 0;
725 }
726 
727 const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = {
728 	.i2c_client_info = vexia_edu_atla10_9v_i2c_clients,
729 	.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients),
730 	.serdev_info = vexia_edu_atla10_9v_serdevs,
731 	.serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs),
732 	.init = vexia_edu_atla10_9v_init,
733 	.use_pci = true,
734 	.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
735 };
736 
737 /*
738  * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node
739  * with three subnodes for each color (B/G/R). The RGB LED node is named
740  * "multi-led" to align with the name in the device tree.
741  */
742 
743 /* Main firmware node for ktd2026 */
744 static const struct software_node ktd2026_node = {
745 	.name = "ktd2026",
746 };
747 
748 static const struct property_entry ktd2026_rgb_led_props[] = {
749 	PROPERTY_ENTRY_U32("reg", 0),
750 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB),
751 	PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"),
752 	PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"),
753 	{ }
754 };
755 
756 static const struct software_node ktd2026_rgb_led_node = {
757 	.name = "multi-led",
758 	.properties = ktd2026_rgb_led_props,
759 	.parent = &ktd2026_node,
760 };
761 
762 static const struct property_entry ktd2026_blue_led_props[] = {
763 	PROPERTY_ENTRY_U32("reg", 0),
764 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),
765 	{ }
766 };
767 
768 static const struct software_node ktd2026_blue_led_node = {
769 	.properties = ktd2026_blue_led_props,
770 	.parent = &ktd2026_rgb_led_node,
771 };
772 
773 static const struct property_entry ktd2026_green_led_props[] = {
774 	PROPERTY_ENTRY_U32("reg", 1),
775 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),
776 	{ }
777 };
778 
779 static const struct software_node ktd2026_green_led_node = {
780 	.properties = ktd2026_green_led_props,
781 	.parent = &ktd2026_rgb_led_node,
782 };
783 
784 static const struct property_entry ktd2026_red_led_props[] = {
785 	PROPERTY_ENTRY_U32("reg", 2),
786 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),
787 	{ }
788 };
789 
790 static const struct software_node ktd2026_red_led_node = {
791 	.properties = ktd2026_red_led_props,
792 	.parent = &ktd2026_rgb_led_node,
793 };
794 
795 static const struct software_node *ktd2026_node_group[] = {
796 	&ktd2026_node,
797 	&ktd2026_rgb_led_node,
798 	&ktd2026_red_led_node,
799 	&ktd2026_green_led_node,
800 	&ktd2026_blue_led_node,
801 	NULL
802 };
803 
804 /*
805  * For the LEDs which backlight the Menu / Home / Back capacitive buttons on
806  * the bottom bezel. These are attached to a TPS61158 LED controller which
807  * is controlled by the "pwm_soc_lpss_2" PWM output.
808  */
809 #define XIAOMI_MIPAD2_LED_PERIOD_NS		19200
810 #define XIAOMI_MIPAD2_LED_MAX_DUTY_NS		 6000 /* From Android kernel */
811 
812 static struct pwm_device *xiaomi_mipad2_led_pwm;
813 
814 static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
815 					enum led_brightness val)
816 {
817 	struct pwm_state state = {
818 		.period = XIAOMI_MIPAD2_LED_PERIOD_NS,
819 		.duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
820 		/* Always set PWM enabled to avoid the pin floating */
821 		.enabled = true,
822 	};
823 
824 	return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
825 }
826 
827 static int __init xiaomi_mipad2_init(struct device *dev)
828 {
829 	struct led_classdev *led_cdev;
830 
831 	xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2");
832 	if (IS_ERR(xiaomi_mipad2_led_pwm))
833 		return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n");
834 
835 	led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
836 	if (!led_cdev)
837 		return -ENOMEM;
838 
839 	led_cdev->name = "mipad2:white:touch-buttons-backlight";
840 	led_cdev->max_brightness = LED_FULL;
841 	led_cdev->default_trigger = "input-events";
842 	led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
843 	/* Turn LED off during suspend */
844 	led_cdev->flags = LED_CORE_SUSPENDRESUME;
845 
846 	return devm_led_classdev_register(dev, led_cdev);
847 }
848 
849 /*
850  * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
851  * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
852  * a bunch of devices to be hidden.
853  *
854  * This takes care of instantiating the hidden devices manually.
855  */
856 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
857 	{
858 		/* BQ27520 fuel-gauge */
859 		.board_info = {
860 			.type = "bq27520",
861 			.addr = 0x55,
862 			.dev_name = "bq27520",
863 			.swnode = &fg_bq25890_supply_node,
864 		},
865 		.adapter_path = "\\_SB_.PCI0.I2C1",
866 	}, {
867 		/* KTD2026 RGB notification LED controller */
868 		.board_info = {
869 			.type = "ktd2026",
870 			.addr = 0x30,
871 			.dev_name = "ktd2026",
872 			.swnode = &ktd2026_node,
873 		},
874 		.adapter_path = "\\_SB_.PCI0.I2C3",
875 	},
876 };
877 
878 const struct x86_dev_info xiaomi_mipad2_info __initconst = {
879 	.i2c_client_info = xiaomi_mipad2_i2c_clients,
880 	.i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
881 	.swnode_group = ktd2026_node_group,
882 	.init = xiaomi_mipad2_init,
883 };
884