1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Board info for Lenovo X86 tablets which ship with Android as the factory image
4 * and which have broken DSDT tables. 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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13#include <linux/efi.h>
14#include <linux/gpio/machine.h>
15#include <linux/mfd/arizona/pdata.h>
16#include <linux/mfd/arizona/registers.h>
17#include <linux/mfd/intel_soc_pmic.h>
18#include <linux/pinctrl/consumer.h>
19#include <linux/pinctrl/machine.h>
20#include <linux/platform_data/lp855x.h>
21#include <linux/platform_device.h>
22#include <linux/reboot.h>
23#include <linux/rmi.h>
24#include <linux/spi/spi.h>
25
26#include "shared-psy-info.h"
27#include "x86-android-tablets.h"
28
29/*
30 * Various Lenovo models use a TI LP8557 LED backlight controller with its PWM
31 * input connected to a PWM output coming from the LCD panel's controller.
32 * The Android kernels have a hack in the i915 driver to write a non-standard
33 * panel specific DSI register to set the duty-cycle of the LCD's PWM output.
34 *
35 * To avoid having to have a similar hack in the mainline kernel program the
36 * LP8557 to directly set the level and use the lp855x_bl driver for control.
37 *
38 * The LP8557 can either be configured to multiply its PWM input and
39 * the I2C register set level (requiring both to be at 100% for 100% output);
40 * or to only take the I2C register set level into account.
41 *
42 * Multiplying the 2 levels is useful because this will turn off the backlight
43 * when the panel goes off and turns off its PWM output.
44 *
45 * But on some models the panel's PWM output defaults to a duty-cycle of
46 * much less then 100%, severely limiting max brightness. In this case
47 * the LP8557 should be configured to only take the I2C register into
48 * account and the i915 driver must turn off the panel and the backlight
49 * separately using e.g. VBT MIPI sequences to turn off the backlight.
50 */
51static struct lp855x_platform_data lenovo_lp8557_pwm_and_reg_pdata = {
52 .device_control = 0x86,
53 .initial_brightness = 128,
54};
55
56static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = {
57 .device_control = 0x85,
58 .initial_brightness = 128,
59};
60
61/* Lenovo Yoga Book X90F / X90L's Android factory img has everything hardcoded */
62
63static const struct property_entry lenovo_yb1_x90_wacom_props[] = {
64 PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001),
65 PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 150),
66 { }
67};
68
69static const struct software_node lenovo_yb1_x90_wacom_node = {
70 .properties = lenovo_yb1_x90_wacom_props,
71};
72
73/*
74 * The HiDeep IST940E touchscreen comes up in I2C-HID mode. The native protocol
75 * reports ABS_MT_PRESSURE and ABS_MT_TOUCH_MAJOR which are not reported in HID
76 * mode, so using native mode is preferred.
77 * It could alternatively be used in HID mode by changing the properties to:
78 * PROPERTY_ENTRY_U32("hid-descr-addr", 0x0020),
79 * PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
80 * and changing board_info.type to "hid-over-i2c".
81 */
82static const struct property_entry lenovo_yb1_x90_hideep_ts_props[] = {
83 PROPERTY_ENTRY_U32("touchscreen-size-x", 1200),
84 PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
85 PROPERTY_ENTRY_U32("touchscreen-max-pressure", 16384),
86 PROPERTY_ENTRY_BOOL("hideep,force-native-protocol"),
87 { }
88};
89
90static const struct software_node lenovo_yb1_x90_hideep_ts_node = {
91 .properties = lenovo_yb1_x90_hideep_ts_props,
92};
93
94static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst = {
95 {
96 /* BQ27542 fuel-gauge */
97 .board_info = {
98 .type = "bq27542",
99 .addr = 0x55,
100 .dev_name = "bq27542",
101 .swnode = &fg_bq25890_supply_node,
102 },
103 .adapter_path = "\\_SB_.PCI0.I2C1",
104 }, {
105 /* Goodix Touchscreen in keyboard half */
106 .board_info = {
107 .type = "GDIX1001:00",
108 .addr = 0x14,
109 .dev_name = "goodix_ts",
110 },
111 .adapter_path = "\\_SB_.PCI0.I2C2",
112 .irq_data = {
113 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
114 .chip = "INT33FF:01",
115 .index = 56,
116 .trigger = ACPI_EDGE_SENSITIVE,
117 .polarity = ACPI_ACTIVE_LOW,
118 .con_id = "goodix_ts_irq",
119 .free_gpio = true,
120 },
121 }, {
122 /* Wacom Digitizer in keyboard half */
123 .board_info = {
124 .type = "hid-over-i2c",
125 .addr = 0x09,
126 .dev_name = "wacom",
127 .swnode = &lenovo_yb1_x90_wacom_node,
128 },
129 .adapter_path = "\\_SB_.PCI0.I2C4",
130 .irq_data = {
131 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
132 .chip = "INT33FF:01",
133 .index = 49,
134 .trigger = ACPI_LEVEL_SENSITIVE,
135 .polarity = ACPI_ACTIVE_LOW,
136 .con_id = "wacom_irq",
137 },
138 }, {
139 /* LP8557 Backlight controller */
140 .board_info = {
141 .type = "lp8557",
142 .addr = 0x2c,
143 .dev_name = "lp8557",
144 .platform_data = &lenovo_lp8557_pwm_and_reg_pdata,
145 },
146 .adapter_path = "\\_SB_.PCI0.I2C4",
147 }, {
148 /* HiDeep IST940E Touchscreen in display half */
149 .board_info = {
150 .type = "hideep_ts",
151 .addr = 0x6c,
152 .dev_name = "hideep_ts",
153 .swnode = &lenovo_yb1_x90_hideep_ts_node,
154 },
155 .adapter_path = "\\_SB_.PCI0.I2C6",
156 .irq_data = {
157 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
158 .chip = "INT33FF:03",
159 .index = 77,
160 .trigger = ACPI_LEVEL_SENSITIVE,
161 .polarity = ACPI_ACTIVE_LOW,
162 .con_id = "hideep_ts_irq",
163 },
164 },
165};
166
167static const struct platform_device_info lenovo_yb1_x90_pdevs[] __initconst = {
168 {
169 .name = "yogabook-touch-kbd-digitizer-switch",
170 .id = PLATFORM_DEVID_NONE,
171 },
172};
173
174/*
175 * DSDT says UART path is "\\_SB.PCIO.URT1" with a letter 'O' instead of
176 * the number '0' add the link manually.
177 */
178static const struct x86_serdev_info lenovo_yb1_x90_serdevs[] __initconst = {
179 {
180 .ctrl_hid = "8086228A",
181 .ctrl_uid = "1",
182 .ctrl_devname = "serial0",
183 .serdev_hid = "BCM2E1A",
184 },
185};
186
187static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst = {
188 .button = {
189 .code = SW_LID,
190 .active_low = true,
191 .desc = "lid_sw",
192 .type = EV_SW,
193 .wakeup = true,
194 .debounce_interval = 50,
195 },
196 .chip = "INT33FF:02",
197 .pin = 19,
198};
199
200static struct gpiod_lookup_table lenovo_yb1_x90_goodix_gpios = {
201 .dev_id = "i2c-goodix_ts",
202 .table = {
203 GPIO_LOOKUP("INT33FF:01", 53, "reset", GPIO_ACTIVE_HIGH),
204 GPIO_LOOKUP("INT33FF:01", 56, "irq", GPIO_ACTIVE_HIGH),
205 { }
206 },
207};
208
209static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios = {
210 .dev_id = "i2c-hideep_ts",
211 .table = {
212 GPIO_LOOKUP("INT33FF:00", 7, "reset", GPIO_ACTIVE_LOW),
213 { }
214 },
215};
216
217static struct gpiod_lookup_table lenovo_yb1_x90_wacom_gpios = {
218 .dev_id = "i2c-wacom",
219 .table = {
220 GPIO_LOOKUP("INT33FF:00", 82, "reset", GPIO_ACTIVE_LOW),
221 { }
222 },
223};
224
225static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = {
226 &lenovo_yb1_x90_hideep_gpios,
227 &lenovo_yb1_x90_goodix_gpios,
228 &lenovo_yb1_x90_wacom_gpios,
229 NULL
230};
231
232static int __init lenovo_yb1_x90_init(void)
233{
234 /* Enable the regulators used by the touchscreens */
235
236 /* Vprog3B 3.0V used by the goodix touchscreen in the keyboard half */
237 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0x9b, value: 0x02, mask: 0xff);
238
239 /* Vprog4D 3.0V used by the HiDeep touchscreen in the display half */
240 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0x9f, value: 0x02, mask: 0xff);
241
242 /* Vprog5A 1.8V used by the HiDeep touchscreen in the display half */
243 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0xa0, value: 0x02, mask: 0xff);
244
245 /* Vprog5B 1.8V used by the goodix touchscreen in the keyboard half */
246 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0xa1, value: 0x02, mask: 0xff);
247
248 return 0;
249}
250
251const struct x86_dev_info lenovo_yogabook_x90_info __initconst = {
252 .i2c_client_info = lenovo_yb1_x90_i2c_clients,
253 .i2c_client_count = ARRAY_SIZE(lenovo_yb1_x90_i2c_clients),
254 .pdev_info = lenovo_yb1_x90_pdevs,
255 .pdev_count = ARRAY_SIZE(lenovo_yb1_x90_pdevs),
256 .serdev_info = lenovo_yb1_x90_serdevs,
257 .serdev_count = ARRAY_SIZE(lenovo_yb1_x90_serdevs),
258 .gpio_button = &lenovo_yb1_x90_lid,
259 .gpio_button_count = 1,
260 .gpiod_lookup_tables = lenovo_yb1_x90_gpios,
261 .init = lenovo_yb1_x90_init,
262};
263
264/* Lenovo Yoga Book X91F/L Windows tablet needs manual instantiation of the fg client */
265static const struct x86_i2c_client_info lenovo_yogabook_x91_i2c_clients[] __initconst = {
266 {
267 /* BQ27542 fuel-gauge */
268 .board_info = {
269 .type = "bq27542",
270 .addr = 0x55,
271 .dev_name = "bq27542",
272 .swnode = &fg_bq25890_supply_node,
273 },
274 .adapter_path = "\\_SB_.PCI0.I2C1",
275 },
276};
277
278const struct x86_dev_info lenovo_yogabook_x91_info __initconst = {
279 .i2c_client_info = lenovo_yogabook_x91_i2c_clients,
280 .i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x91_i2c_clients),
281};
282
283/* Lenovo Yoga Tablet 2 1050F/L's Android factory img has everything hardcoded */
284static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = {
285 PROPERTY_ENTRY_STRING_ARRAY_LEN("supplied-from", tusb1211_chg_det_psy, 1),
286 PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node),
287 PROPERTY_ENTRY_BOOL("omit-battery-class"),
288 PROPERTY_ENTRY_BOOL("disable-reset"),
289 { }
290};
291
292static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node = {
293 .properties = lenovo_yoga_tab2_830_1050_bq24190_props,
294};
295
296static const struct x86_gpio_button lenovo_yoga_tab2_830_1050_lid __initconst = {
297 .button = {
298 .code = SW_LID,
299 .active_low = true,
300 .desc = "lid_sw",
301 .type = EV_SW,
302 .wakeup = true,
303 .debounce_interval = 50,
304 },
305 .chip = "INT33FC:02",
306 .pin = 26,
307};
308
309/* This gets filled by lenovo_yoga_tab2_830_1050_init() */
310static struct rmi_device_platform_data lenovo_yoga_tab2_830_1050_rmi_pdata = { };
311
312static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initdata = {
313 {
314 /*
315 * This must be the first entry because lenovo_yoga_tab2_830_1050_init()
316 * may update its swnode. LSM303DA accelerometer + magnetometer.
317 */
318 .board_info = {
319 .type = "lsm303d",
320 .addr = 0x1d,
321 .dev_name = "lsm303d",
322 },
323 .adapter_path = "\\_SB_.I2C5",
324 }, {
325 /* AL3320A ambient light sensor */
326 .board_info = {
327 .type = "al3320a",
328 .addr = 0x1c,
329 .dev_name = "al3320a",
330 },
331 .adapter_path = "\\_SB_.I2C5",
332 }, {
333 /* bq24292i battery charger */
334 .board_info = {
335 .type = "bq24190",
336 .addr = 0x6b,
337 .dev_name = "bq24292i",
338 .swnode = &lenovo_yoga_tab2_830_1050_bq24190_node,
339 .platform_data = &bq24190_pdata,
340 },
341 .adapter_path = "\\_SB_.I2C1",
342 .irq_data = {
343 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
344 .chip = "INT33FC:02",
345 .index = 2,
346 .trigger = ACPI_EDGE_SENSITIVE,
347 .polarity = ACPI_ACTIVE_HIGH,
348 .con_id = "bq24292i_irq",
349 },
350 }, {
351 /* BQ27541 fuel-gauge */
352 .board_info = {
353 .type = "bq27541",
354 .addr = 0x55,
355 .dev_name = "bq27541",
356 .swnode = &fg_bq24190_supply_node,
357 },
358 .adapter_path = "\\_SB_.I2C1",
359 }, {
360 /* Synaptics RMI touchscreen */
361 .board_info = {
362 .type = "rmi4_i2c",
363 .addr = 0x38,
364 .dev_name = "rmi4_i2c",
365 .platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata,
366 },
367 .adapter_path = "\\_SB_.I2C6",
368 .irq_data = {
369 .type = X86_ACPI_IRQ_TYPE_APIC,
370 .index = 0x45,
371 .trigger = ACPI_EDGE_SENSITIVE,
372 .polarity = ACPI_ACTIVE_HIGH,
373 },
374 }, {
375 /* LP8557 Backlight controller */
376 .board_info = {
377 .type = "lp8557",
378 .addr = 0x2c,
379 .dev_name = "lp8557",
380 .platform_data = &lenovo_lp8557_pwm_and_reg_pdata,
381 },
382 .adapter_path = "\\_SB_.I2C3",
383 },
384};
385
386static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios = {
387 .dev_id = "intel-int3496",
388 .table = {
389 GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_LOW),
390 GPIO_LOOKUP("INT33FC:02", 24, "id", GPIO_ACTIVE_HIGH),
391 { }
392 },
393};
394
395#define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00"
396
397static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_codec_gpios = {
398 .dev_id = LENOVO_YOGA_TAB2_830_1050_CODEC_NAME,
399 .table = {
400 GPIO_LOOKUP("gpio_crystalcove", 3, "reset", GPIO_ACTIVE_HIGH),
401 GPIO_LOOKUP("INT33FC:01", 23, "wlf,ldoena", GPIO_ACTIVE_HIGH),
402 GPIO_LOOKUP("arizona", 2, "wlf,spkvdd-ena", GPIO_ACTIVE_HIGH),
403 GPIO_LOOKUP("arizona", 4, "wlf,micd-pol", GPIO_ACTIVE_LOW),
404 { }
405 },
406};
407
408static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = {
409 &lenovo_yoga_tab2_830_1050_int3496_gpios,
410 &lenovo_yoga_tab2_830_1050_codec_gpios,
411 NULL
412};
413
414static int __init lenovo_yoga_tab2_830_1050_init(void);
415static void lenovo_yoga_tab2_830_1050_exit(void);
416
417const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = {
418 .i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients,
419 .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients),
420 .pdev_info = int3496_pdevs,
421 .pdev_count = 1,
422 .gpio_button = &lenovo_yoga_tab2_830_1050_lid,
423 .gpio_button_count = 1,
424 .gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios,
425 .bat_swnode = &generic_lipo_hv_4v35_battery_node,
426 .modules = bq24190_modules,
427 .init = lenovo_yoga_tab2_830_1050_init,
428 .exit = lenovo_yoga_tab2_830_1050_exit,
429};
430
431/*
432 * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same
433 * mainboard, but the 830 uses a portrait LCD panel with a landscape touchscreen,
434 * requiring the touchscreen driver to adjust the touch-coords to match the LCD.
435 * And requiring the accelerometer to have a mount-matrix set to correct for
436 * the 90° rotation of the LCD vs the frame.
437 */
438static const char * const lenovo_yoga_tab2_830_lms303d_mount_matrix[] = {
439 "0", "1", "0",
440 "-1", "0", "0",
441 "0", "0", "1"
442};
443
444static const struct property_entry lenovo_yoga_tab2_830_lms303d_props[] = {
445 PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", lenovo_yoga_tab2_830_lms303d_mount_matrix),
446 { }
447};
448
449static const struct software_node lenovo_yoga_tab2_830_lms303d_node = {
450 .properties = lenovo_yoga_tab2_830_lms303d_props,
451};
452
453static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
454{
455 struct gpio_desc *gpiod;
456 int ret;
457
458 /* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
459 ret = x86_android_tablet_get_gpiod(chip: "gpio_crystalcove", pin: 10, con_id: "yoga_bootstrap",
460 active_low: false, dflags: GPIOD_ASIS, desc: &gpiod);
461 if (ret)
462 return ret;
463
464 ret = gpiod_get_value_cansleep(desc: gpiod);
465 if (ret) {
466 pr_info("detected Lenovo Yoga Tablet 2 1050F/L\n");
467 } else {
468 pr_info("detected Lenovo Yoga Tablet 2 830F/L\n");
469 lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.swap_axes = true;
470 lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.flip_y = true;
471 lenovo_yoga_tab2_830_1050_i2c_clients[0].board_info.swnode =
472 &lenovo_yoga_tab2_830_lms303d_node;
473 }
474
475 return 0;
476}
477
478/* SUS (INT33FC:02) pin 6 needs to be configured as pmu_clk for the audio codec */
479static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =
480 PIN_MAP_MUX_GROUP(LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, "codec_32khz_clk",
481 "INT33FC:02", "pmu_clk2_grp", "pmu_clk");
482
483static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
484static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;
485
486static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
487{
488 struct device *codec_dev;
489 struct pinctrl *pinctrl;
490 int ret;
491
492 codec_dev = bus_find_device_by_name(bus: &spi_bus_type, NULL,
493 LENOVO_YOGA_TAB2_830_1050_CODEC_NAME);
494 if (!codec_dev) {
495 pr_err("error cannot find %s device\n", LENOVO_YOGA_TAB2_830_1050_CODEC_NAME);
496 return -ENODEV;
497 }
498
499 ret = pinctrl_register_mappings(map: &lenovo_yoga_tab2_830_1050_codec_pinctrl_map, num_maps: 1);
500 if (ret)
501 goto err_put_device;
502
503 pinctrl = pinctrl_get_select(dev: codec_dev, name: "codec_32khz_clk");
504 if (IS_ERR(ptr: pinctrl)) {
505 ret = dev_err_probe(dev: codec_dev, err: PTR_ERR(ptr: pinctrl), fmt: "selecting codec_32khz_clk\n");
506 goto err_unregister_mappings;
507 }
508
509 /* We're done with the codec_dev now */
510 put_device(dev: codec_dev);
511
512 lenovo_yoga_tab2_830_1050_codec_pinctrl = pinctrl;
513 return 0;
514
515err_unregister_mappings:
516 pinctrl_unregister_mappings(map: &lenovo_yoga_tab2_830_1050_codec_pinctrl_map);
517err_put_device:
518 put_device(dev: codec_dev);
519 return ret;
520}
521
522/*
523 * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off
524 * gets used as pm_power_off handler. This causes "poweroff" on these tablets
525 * to hang hard. Requiring pressing the powerbutton for 30 seconds *twice*
526 * followed by a normal 3 second press to recover. Avoid this by doing an EFI
527 * poweroff instead.
528 */
529static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
530{
531 efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
532
533 return NOTIFY_DONE;
534}
535
536static int __init lenovo_yoga_tab2_830_1050_init(void)
537{
538 int ret;
539
540 ret = lenovo_yoga_tab2_830_1050_init_touchscreen();
541 if (ret)
542 return ret;
543
544 ret = lenovo_yoga_tab2_830_1050_init_codec();
545 if (ret)
546 return ret;
547
548 /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
549 lenovo_yoga_tab2_830_1050_sys_off_handler =
550 register_sys_off_handler(mode: SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
551 callback: lenovo_yoga_tab2_830_1050_power_off, NULL);
552 if (IS_ERR(ptr: lenovo_yoga_tab2_830_1050_sys_off_handler))
553 return PTR_ERR(ptr: lenovo_yoga_tab2_830_1050_sys_off_handler);
554
555 return 0;
556}
557
558static void lenovo_yoga_tab2_830_1050_exit(void)
559{
560 unregister_sys_off_handler(handler: lenovo_yoga_tab2_830_1050_sys_off_handler);
561
562 if (lenovo_yoga_tab2_830_1050_codec_pinctrl) {
563 pinctrl_put(p: lenovo_yoga_tab2_830_1050_codec_pinctrl);
564 pinctrl_unregister_mappings(map: &lenovo_yoga_tab2_830_1050_codec_pinctrl_map);
565 }
566}
567
568/* Lenovo Yoga Tab 3 Pro YT3-X90F */
569
570/*
571 * There are 2 batteries, with 2 bq27500 fuel-gauges and 2 bq25892 chargers,
572 * "bq25890-charger-1" is instantiated from: drivers/i2c/busses/i2c-cht-wc.c.
573 */
574static const char * const lenovo_yt3_bq25892_0_suppliers[] = { "cht_wcove_pwrsrc" };
575static const char * const bq25890_1_psy[] = { "bq25890-charger-1" };
576
577static const struct property_entry fg_bq25890_1_supply_props[] = {
578 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_1_psy),
579 { }
580};
581
582static const struct software_node fg_bq25890_1_supply_node = {
583 .properties = fg_bq25890_1_supply_props,
584};
585
586/* bq25892 charger settings for the flat lipo battery behind the screen */
587static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
588 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
589 PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
590 PROPERTY_ENTRY_BOOL("linux,skip-reset"),
591 /* Values taken from Android Factory Image */
592 PROPERTY_ENTRY_U32("ti,charge-current", 2048000),
593 PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
594 PROPERTY_ENTRY_U32("ti,termination-current", 128000),
595 PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
596 PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
597 PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
598 PROPERTY_ENTRY_U32("ti,boost-max-current", 500000),
599 PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
600 { }
601};
602
603static const struct software_node lenovo_yt3_bq25892_0_node = {
604 .properties = lenovo_yt3_bq25892_0_props,
605};
606
607static const struct property_entry lenovo_yt3_hideep_ts_props[] = {
608 PROPERTY_ENTRY_U32("touchscreen-size-x", 1600),
609 PROPERTY_ENTRY_U32("touchscreen-size-y", 2560),
610 PROPERTY_ENTRY_U32("touchscreen-max-pressure", 255),
611 { }
612};
613
614static const struct software_node lenovo_yt3_hideep_ts_node = {
615 .properties = lenovo_yt3_hideep_ts_props,
616};
617
618static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
619 {
620 /* bq27500 fuel-gauge for the flat lipo battery behind the screen */
621 .board_info = {
622 .type = "bq27500",
623 .addr = 0x55,
624 .dev_name = "bq27500_0",
625 .swnode = &fg_bq25890_supply_node,
626 },
627 .adapter_path = "\\_SB_.PCI0.I2C1",
628 }, {
629 /* bq25892 charger for the flat lipo battery behind the screen */
630 .board_info = {
631 .type = "bq25892",
632 .addr = 0x6b,
633 .dev_name = "bq25892_0",
634 .swnode = &lenovo_yt3_bq25892_0_node,
635 },
636 .adapter_path = "\\_SB_.PCI0.I2C1",
637 .irq_data = {
638 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
639 .chip = "INT33FF:01",
640 .index = 5,
641 .trigger = ACPI_EDGE_SENSITIVE,
642 .polarity = ACPI_ACTIVE_LOW,
643 .con_id = "bq25892_0_irq",
644 },
645 }, {
646 /* bq27500 fuel-gauge for the round li-ion cells in the hinge */
647 .board_info = {
648 .type = "bq27500",
649 .addr = 0x55,
650 .dev_name = "bq27500_1",
651 .swnode = &fg_bq25890_1_supply_node,
652 },
653 .adapter_path = "\\_SB_.PCI0.I2C2",
654 }, {
655 /* HiDeep IST520E Touchscreen */
656 .board_info = {
657 .type = "hideep_ts",
658 .addr = 0x6c,
659 .dev_name = "hideep_ts",
660 .swnode = &lenovo_yt3_hideep_ts_node,
661 },
662 .adapter_path = "\\_SB_.PCI0.I2C6",
663 .irq_data = {
664 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
665 .chip = "INT33FF:03",
666 .index = 77,
667 .trigger = ACPI_LEVEL_SENSITIVE,
668 .polarity = ACPI_ACTIVE_LOW,
669 .con_id = "hideep_ts_irq",
670 },
671 }, {
672 /* LP8557 Backlight controller */
673 .board_info = {
674 .type = "lp8557",
675 .addr = 0x2c,
676 .dev_name = "lp8557",
677 .platform_data = &lenovo_lp8557_reg_only_pdata,
678 },
679 .adapter_path = "\\_SB_.PCI0.I2C1",
680 }
681};
682
683/*
684 * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
685 * Function A Play/Pause: 0 ohm
686 * Function D Voice assistant: 135 ohm
687 * Function B Volume Up 240 ohm
688 * Function C Volume Down 470 ohm
689 * Minimum Mic DC resistance 1000 ohm
690 * Minimum Ear speaker impedance 16 ohm
691 * Note the first max value below must be less then the min. speaker impedance,
692 * to allow CTIA/OMTP detection to work. The other max values are the closest
693 * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
694 */
695static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
696 { .max = 11, .key = KEY_PLAYPAUSE },
697 { .max = 186, .key = KEY_VOICECOMMAND },
698 { .max = 348, .key = KEY_VOLUMEUP },
699 { .max = 752, .key = KEY_VOLUMEDOWN },
700};
701
702/* YT3 WM5102 arizona_micd_config comes from Android kernel sources */
703static struct arizona_micd_config lenovo_yt3_wm5102_micd_config[] = {
704 { 0, 1, 0 },
705 { ARIZONA_ACCDET_SRC, 2, 1 },
706};
707
708static struct arizona_pdata lenovo_yt3_wm5102_pdata = {
709 .irq_flags = IRQF_TRIGGER_LOW,
710 .micd_detect_debounce = 200,
711 .micd_ranges = arizona_micd_aosp_ranges,
712 .num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges),
713 .hpdet_channel = ARIZONA_ACCDET_MODE_HPL,
714
715 /* Below settings come from Android kernel sources */
716 .micd_bias_start_time = 1,
717 .micd_rate = 6,
718 .micd_configs = lenovo_yt3_wm5102_micd_config,
719 .num_micd_configs = ARRAY_SIZE(lenovo_yt3_wm5102_micd_config),
720 .micbias = {
721 [0] = { /* MICBIAS1 */
722 .mV = 2800,
723 .ext_cap = 1,
724 .discharge = 1,
725 .soft_start = 0,
726 .bypass = 0,
727 },
728 [1] = { /* MICBIAS2 */
729 .mV = 2800,
730 .ext_cap = 1,
731 .discharge = 1,
732 .soft_start = 0,
733 .bypass = 0,
734 },
735 [2] = { /* MICBIAS2 */
736 .mV = 2800,
737 .ext_cap = 1,
738 .discharge = 1,
739 .soft_start = 0,
740 .bypass = 0,
741 },
742 },
743};
744
745static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = {
746 {
747 /* WM5102 codec */
748 .board_info = {
749 .modalias = "wm5102",
750 .platform_data = &lenovo_yt3_wm5102_pdata,
751 .max_speed_hz = 5000000,
752 },
753 .ctrl_path = "\\_SB_.PCI0.SPI1",
754 .irq_data = {
755 .type = X86_ACPI_IRQ_TYPE_GPIOINT,
756 .chip = "INT33FF:00",
757 .index = 91,
758 .trigger = ACPI_LEVEL_SENSITIVE,
759 .polarity = ACPI_ACTIVE_LOW,
760 .con_id = "wm5102_irq",
761 },
762 }
763};
764
765static int __init lenovo_yt3_init(void)
766{
767 int ret;
768
769 /*
770 * The "bq25892_0" charger IC has its /CE (Charge-Enable) and OTG pins
771 * connected to GPIOs, rather then having them hardwired to the correct
772 * values as is normally done.
773 *
774 * The bq25890_charger driver controls these through I2C, but this only
775 * works if not overridden by the pins. Set these pins here:
776 * 1. Set /CE to 1 to allow charging.
777 * 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
778 * the main "bq25892_1" charger is used when necessary.
779 */
780
781 /* /CE pin */
782 ret = x86_android_tablet_get_gpiod(chip: "INT33FF:02", pin: 22, con_id: "bq25892_0_ce",
783 active_low: true, dflags: GPIOD_OUT_HIGH, NULL);
784 if (ret < 0)
785 return ret;
786
787 /* OTG pin */
788 ret = x86_android_tablet_get_gpiod(chip: "INT33FF:03", pin: 19, con_id: "bq25892_0_otg",
789 active_low: false, dflags: GPIOD_OUT_LOW, NULL);
790 if (ret < 0)
791 return ret;
792
793 /* Enable the regulators used by the touchscreen */
794 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0x9b, value: 0x02, mask: 0xff);
795 intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address: 0x6e, reg_address: 0xa0, value: 0x02, mask: 0xff);
796
797 return 0;
798}
799
800static struct gpiod_lookup_table lenovo_yt3_hideep_gpios = {
801 .dev_id = "i2c-hideep_ts",
802 .table = {
803 GPIO_LOOKUP("INT33FF:00", 7, "reset", GPIO_ACTIVE_LOW),
804 { }
805 },
806};
807
808static struct gpiod_lookup_table lenovo_yt3_wm5102_gpios = {
809 .dev_id = "spi1.0",
810 .table = {
811 GPIO_LOOKUP("INT33FF:00", 75, "wlf,spkvdd-ena", GPIO_ACTIVE_HIGH),
812 GPIO_LOOKUP("INT33FF:00", 81, "wlf,ldoena", GPIO_ACTIVE_HIGH),
813 GPIO_LOOKUP("INT33FF:00", 82, "reset", GPIO_ACTIVE_HIGH),
814 GPIO_LOOKUP("arizona", 2, "wlf,micd-pol", GPIO_ACTIVE_HIGH),
815 { }
816 },
817};
818
819static struct gpiod_lookup_table * const lenovo_yt3_gpios[] = {
820 &lenovo_yt3_hideep_gpios,
821 &lenovo_yt3_wm5102_gpios,
822 NULL
823};
824
825const struct x86_dev_info lenovo_yt3_info __initconst = {
826 .i2c_client_info = lenovo_yt3_i2c_clients,
827 .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients),
828 .spi_dev_info = lenovo_yt3_spi_devs,
829 .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs),
830 .gpiod_lookup_tables = lenovo_yt3_gpios,
831 .init = lenovo_yt3_init,
832};
833

source code of linux/drivers/platform/x86/x86-android-tablets/lenovo.c