xref: /linux/drivers/platform/x86/x86-android-tablets/other.c (revision 8499899816fd79aefdfa923ed3fb5a15b0a62757)
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 
chuwi_hi8_init(struct device * dev)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 
czc_p10t_init(struct device * dev)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 5V, Android 4.4 + Guadalinex Ubuntu tablet
603  * distributed to schools in the Spanish Andalucía region.
604  */
605 static const struct property_entry vexia_edu_atla10_5v_touchscreen_props[] = {
606 	PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
607 	PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
608 	{ }
609 };
610 
611 static const struct software_node vexia_edu_atla10_5v_touchscreen_node = {
612 	.properties = vexia_edu_atla10_5v_touchscreen_props,
613 };
614 
615 static const struct x86_i2c_client_info vexia_edu_atla10_5v_i2c_clients[] __initconst = {
616 	{
617 		/* kxcjk1013 accelerometer */
618 		.board_info = {
619 			.type = "kxcjk1013",
620 			.addr = 0x0f,
621 			.dev_name = "kxcjk1013",
622 		},
623 		.adapter_path = "\\_SB_.I2C3",
624 	}, {
625 		/*  touchscreen controller */
626 		.board_info = {
627 			.type = "hid-over-i2c",
628 			.addr = 0x38,
629 			.dev_name = "FTSC1000",
630 			.swnode = &vexia_edu_atla10_5v_touchscreen_node,
631 		},
632 		.adapter_path = "\\_SB_.I2C4",
633 		.irq_data = {
634 			.type = X86_ACPI_IRQ_TYPE_APIC,
635 			.index = 0x44,
636 			.trigger = ACPI_LEVEL_SENSITIVE,
637 			.polarity = ACPI_ACTIVE_HIGH,
638 		},
639 	}
640 };
641 
642 static struct gpiod_lookup_table vexia_edu_atla10_5v_ft5416_gpios = {
643 	.dev_id = "i2c-FTSC1000",
644 	.table = {
645 		GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_LOW),
646 		{ }
647 	},
648 };
649 
650 static struct gpiod_lookup_table * const vexia_edu_atla10_5v_gpios[] = {
651 	&vexia_edu_atla10_5v_ft5416_gpios,
652 	NULL
653 };
654 
655 const struct x86_dev_info vexia_edu_atla10_5v_info __initconst = {
656 	.i2c_client_info = vexia_edu_atla10_5v_i2c_clients,
657 	.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_5v_i2c_clients),
658 	.gpiod_lookup_tables = vexia_edu_atla10_5v_gpios,
659 };
660 
661 /*
662  * Vexia EDU ATLA 10 tablet 9V, Android 4.2 + Guadalinex Ubuntu tablet
663  * distributed to schools in the Spanish Andalucía region.
664  */
665 static const char * const crystal_cove_pwrsrc_psy[] = { "crystal_cove_pwrsrc" };
666 
667 static const struct property_entry vexia_edu_atla10_9v_ulpmc_props[] = {
668 	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", crystal_cove_pwrsrc_psy),
669 	{ }
670 };
671 
672 static const struct software_node vexia_edu_atla10_9v_ulpmc_node = {
673 	.properties = vexia_edu_atla10_9v_ulpmc_props,
674 };
675 
676 static const char * const vexia_edu_atla10_9v_accel_mount_matrix[] = {
677 	"0", "-1", "0",
678 	"1", "0", "0",
679 	"0", "0", "1"
680 };
681 
682 static const struct property_entry vexia_edu_atla10_9v_accel_props[] = {
683 	PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", vexia_edu_atla10_9v_accel_mount_matrix),
684 	{ }
685 };
686 
687 static const struct software_node vexia_edu_atla10_9v_accel_node = {
688 	.properties = vexia_edu_atla10_9v_accel_props,
689 };
690 
691 static const struct property_entry vexia_edu_atla10_9v_touchscreen_props[] = {
692 	PROPERTY_ENTRY_U32("hid-descr-addr", 0x0000),
693 	PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
694 	{ }
695 };
696 
697 static const struct software_node vexia_edu_atla10_9v_touchscreen_node = {
698 	.properties = vexia_edu_atla10_9v_touchscreen_props,
699 };
700 
701 static const struct property_entry vexia_edu_atla10_9v_pmic_props[] = {
702 	PROPERTY_ENTRY_BOOL("linux,register-pwrsrc-power_supply"),
703 	{ }
704 };
705 
706 static const struct software_node vexia_edu_atla10_9v_pmic_node = {
707 	.properties = vexia_edu_atla10_9v_pmic_props,
708 };
709 
710 static const struct x86_i2c_client_info vexia_edu_atla10_9v_i2c_clients[] __initconst = {
711 	{
712 		/* I2C attached embedded controller, used to access fuel-gauge */
713 		.board_info = {
714 			.type = "vexia_atla10_ec",
715 			.addr = 0x76,
716 			.dev_name = "ulpmc",
717 			.swnode = &vexia_edu_atla10_9v_ulpmc_node,
718 		},
719 		.adapter_path = "0000:00:18.1",
720 	}, {
721 		/* RT5642 audio codec */
722 		.board_info = {
723 			.type = "rt5640",
724 			.addr = 0x1c,
725 			.dev_name = "rt5640",
726 		},
727 		.adapter_path = "0000:00:18.2",
728 		.irq_data = {
729 			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
730 			.chip = "INT33FC:02",
731 			.index = 4,
732 			.trigger = ACPI_EDGE_SENSITIVE,
733 			.polarity = ACPI_ACTIVE_HIGH,
734 			.con_id = "rt5640_irq",
735 		},
736 	}, {
737 		/* kxtj21009 accelerometer */
738 		.board_info = {
739 			.type = "kxtj21009",
740 			.addr = 0x0f,
741 			.dev_name = "kxtj21009",
742 			.swnode = &vexia_edu_atla10_9v_accel_node,
743 		},
744 		.adapter_path = "0000:00:18.5",
745 	}, {
746 		/* FT5416DQ9 touchscreen controller */
747 		.board_info = {
748 			.type = "hid-over-i2c",
749 			.addr = 0x38,
750 			.dev_name = "FTSC1000",
751 			.swnode = &vexia_edu_atla10_9v_touchscreen_node,
752 		},
753 		.adapter_path = "0000:00:18.6",
754 		.irq_data = {
755 			.type = X86_ACPI_IRQ_TYPE_APIC,
756 			.index = 0x45,
757 			.trigger = ACPI_LEVEL_SENSITIVE,
758 			.polarity = ACPI_ACTIVE_HIGH,
759 		},
760 	}, {
761 		/* Crystal Cove PMIC */
762 		.board_info = {
763 			.type = "intel_soc_pmic_crc",
764 			.addr = 0x6e,
765 			.dev_name = "intel_soc_pmic_crc",
766 			.swnode = &vexia_edu_atla10_9v_pmic_node,
767 		},
768 		.adapter_path = "0000:00:18.7",
769 		.irq_data = {
770 			.type = X86_ACPI_IRQ_TYPE_APIC,
771 			.index = 0x43,
772 			.trigger = ACPI_LEVEL_SENSITIVE,
773 			.polarity = ACPI_ACTIVE_HIGH,
774 		},
775 	}
776 };
777 
778 static const struct x86_serdev_info vexia_edu_atla10_9v_serdevs[] __initconst = {
779 	{
780 		.ctrl.pci.devfn = PCI_DEVFN(0x1e, 3),
781 		.ctrl_devname = "serial0",
782 		.serdev_hid = "OBDA8723",
783 	},
784 };
785 
786 static struct gpiod_lookup_table vexia_edu_atla10_9v_ft5416_gpios = {
787 	.dev_id = "i2c-FTSC1000",
788 	.table = {
789 		GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_LOW),
790 		{ }
791 	},
792 };
793 
794 static struct gpiod_lookup_table * const vexia_edu_atla10_9v_gpios[] = {
795 	&vexia_edu_atla10_9v_ft5416_gpios,
796 	NULL
797 };
798 
vexia_edu_atla10_9v_init(struct device * dev)799 static int __init vexia_edu_atla10_9v_init(struct device *dev)
800 {
801 	struct pci_dev *pdev;
802 	int ret;
803 
804 	/* Enable the Wifi module by setting the wifi_enable pin to 1 */
805 	ret = x86_android_tablet_get_gpiod("INT33FC:02", 20, "wifi_enable",
806 					   false, GPIOD_OUT_HIGH, NULL);
807 	if (ret)
808 		return ret;
809 
810 	/* Reprobe the SDIO controller to enumerate the now enabled Wifi module */
811 	pdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x11, 0));
812 	if (!pdev)
813 		return -EPROBE_DEFER;
814 
815 	ret = device_reprobe(&pdev->dev);
816 	if (ret)
817 		pci_warn(pdev, "Reprobing error: %d\n", ret);
818 
819 	pci_dev_put(pdev);
820 	return 0;
821 }
822 
823 const struct x86_dev_info vexia_edu_atla10_9v_info __initconst = {
824 	.i2c_client_info = vexia_edu_atla10_9v_i2c_clients,
825 	.i2c_client_count = ARRAY_SIZE(vexia_edu_atla10_9v_i2c_clients),
826 	.serdev_info = vexia_edu_atla10_9v_serdevs,
827 	.serdev_count = ARRAY_SIZE(vexia_edu_atla10_9v_serdevs),
828 	.gpiod_lookup_tables = vexia_edu_atla10_9v_gpios,
829 	.init = vexia_edu_atla10_9v_init,
830 	.use_pci = true,
831 };
832 
833 /*
834  * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node
835  * with three subnodes for each color (B/G/R). The RGB LED node is named
836  * "multi-led" to align with the name in the device tree.
837  */
838 
839 /* Main firmware node for ktd2026 */
840 static const struct software_node ktd2026_node = {
841 	.name = "ktd2026",
842 };
843 
844 static const struct property_entry ktd2026_rgb_led_props[] = {
845 	PROPERTY_ENTRY_U32("reg", 0),
846 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB),
847 	PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"),
848 	PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"),
849 	{ }
850 };
851 
852 static const struct software_node ktd2026_rgb_led_node = {
853 	.name = "multi-led",
854 	.properties = ktd2026_rgb_led_props,
855 	.parent = &ktd2026_node,
856 };
857 
858 static const struct property_entry ktd2026_blue_led_props[] = {
859 	PROPERTY_ENTRY_U32("reg", 0),
860 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE),
861 	{ }
862 };
863 
864 static const struct software_node ktd2026_blue_led_node = {
865 	.properties = ktd2026_blue_led_props,
866 	.parent = &ktd2026_rgb_led_node,
867 };
868 
869 static const struct property_entry ktd2026_green_led_props[] = {
870 	PROPERTY_ENTRY_U32("reg", 1),
871 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN),
872 	{ }
873 };
874 
875 static const struct software_node ktd2026_green_led_node = {
876 	.properties = ktd2026_green_led_props,
877 	.parent = &ktd2026_rgb_led_node,
878 };
879 
880 static const struct property_entry ktd2026_red_led_props[] = {
881 	PROPERTY_ENTRY_U32("reg", 2),
882 	PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED),
883 	{ }
884 };
885 
886 static const struct software_node ktd2026_red_led_node = {
887 	.properties = ktd2026_red_led_props,
888 	.parent = &ktd2026_rgb_led_node,
889 };
890 
891 static const struct software_node *ktd2026_node_group[] = {
892 	&ktd2026_node,
893 	&ktd2026_rgb_led_node,
894 	&ktd2026_red_led_node,
895 	&ktd2026_green_led_node,
896 	&ktd2026_blue_led_node,
897 	NULL
898 };
899 
900 /*
901  * For the LEDs which backlight the Menu / Home / Back capacitive buttons on
902  * the bottom bezel. These are attached to a TPS61158 LED controller which
903  * is controlled by the "pwm_soc_lpss_2" PWM output.
904  */
905 #define XIAOMI_MIPAD2_LED_PERIOD_NS		19200
906 #define XIAOMI_MIPAD2_LED_MAX_DUTY_NS		 6000 /* From Android kernel */
907 
908 static struct pwm_device *xiaomi_mipad2_led_pwm;
909 
xiaomi_mipad2_brightness_set(struct led_classdev * led_cdev,enum led_brightness val)910 static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
911 					enum led_brightness val)
912 {
913 	struct pwm_state state = {
914 		.period = XIAOMI_MIPAD2_LED_PERIOD_NS,
915 		.duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
916 		/* Always set PWM enabled to avoid the pin floating */
917 		.enabled = true,
918 	};
919 
920 	return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state);
921 }
922 
xiaomi_mipad2_init(struct device * dev)923 static int __init xiaomi_mipad2_init(struct device *dev)
924 {
925 	struct led_classdev *led_cdev;
926 	int ret;
927 
928 	xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2");
929 	if (IS_ERR(xiaomi_mipad2_led_pwm))
930 		return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n");
931 
932 	led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL);
933 	if (!led_cdev)
934 		return -ENOMEM;
935 
936 	led_cdev->name = "mipad2:white:touch-buttons-backlight";
937 	led_cdev->max_brightness = LED_FULL;
938 	led_cdev->default_trigger = "input-events";
939 	led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
940 	/* Turn LED off during suspend */
941 	led_cdev->flags = LED_CORE_SUSPENDRESUME;
942 
943 	ret = devm_led_classdev_register(dev, led_cdev);
944 	if (ret)
945 		return dev_err_probe(dev, ret, "registering LED\n");
946 
947 	return software_node_register_node_group(ktd2026_node_group);
948 }
949 
xiaomi_mipad2_exit(void)950 static void xiaomi_mipad2_exit(void)
951 {
952 	software_node_unregister_node_group(ktd2026_node_group);
953 }
954 
955 /*
956  * If the EFI bootloader is not Xiaomi's own signed Android loader, then the
957  * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing
958  * a bunch of devices to be hidden.
959  *
960  * This takes care of instantiating the hidden devices manually.
961  */
962 static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst = {
963 	{
964 		/* BQ27520 fuel-gauge */
965 		.board_info = {
966 			.type = "bq27520",
967 			.addr = 0x55,
968 			.dev_name = "bq27520",
969 			.swnode = &fg_bq25890_supply_node,
970 		},
971 		.adapter_path = "\\_SB_.PCI0.I2C1",
972 	}, {
973 		/* KTD2026 RGB notification LED controller */
974 		.board_info = {
975 			.type = "ktd2026",
976 			.addr = 0x30,
977 			.dev_name = "ktd2026",
978 			.swnode = &ktd2026_node,
979 		},
980 		.adapter_path = "\\_SB_.PCI0.I2C3",
981 	},
982 };
983 
984 const struct x86_dev_info xiaomi_mipad2_info __initconst = {
985 	.i2c_client_info = xiaomi_mipad2_i2c_clients,
986 	.i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients),
987 	.init = xiaomi_mipad2_init,
988 	.exit = xiaomi_mipad2_exit,
989 };
990