linux/drivers/platform/x86/x86-android-tablets/lenovo.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Board info for Lenovo X86 tablets which ship with Android as the factory image
 * and which have broken DSDT tables. The factory kernels shipped on these
 * devices typically have a bunch of things hardcoded, rather than specified
 * in their DSDT.
 *
 * Copyright (C) 2021-2023 Hans de Goede <[email protected]>
 */

#define pr_fmt(fmt)

#include <linux/efi.h>
#include <linux/gpio/machine.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/platform_data/lp855x.h>
#include <linux/platform_device.h>
#include <linux/power/bq24190_charger.h>
#include <linux/reboot.h>
#include <linux/rmi.h>
#include <linux/spi/spi.h>

#include "shared-psy-info.h"
#include "x86-android-tablets.h"

/*
 * Various Lenovo models use a TI LP8557 LED backlight controller with its PWM
 * input connected to a PWM output coming from the LCD panel's controller.
 * The Android kernels have a hack in the i915 driver to write a non-standard
 * panel specific DSI register to set the duty-cycle of the LCD's PWM output.
 *
 * To avoid having to have a similar hack in the mainline kernel program the
 * LP8557 to directly set the level and use the lp855x_bl driver for control.
 *
 * The LP8557 can either be configured to multiply its PWM input and
 * the I2C register set level (requiring both to be at 100% for 100% output);
 * or to only take the I2C register set level into account.
 *
 * Multiplying the 2 levels is useful because this will turn off the backlight
 * when the panel goes off and turns off its PWM output.
 *
 * But on some models the panel's PWM output defaults to a duty-cycle of
 * much less then 100%, severely limiting max brightness. In this case
 * the LP8557 should be configured to only take the I2C register into
 * account and the i915 driver must turn off the panel and the backlight
 * separately using e.g. VBT MIPI sequences to turn off the backlight.
 */
static struct lp855x_platform_data lenovo_lp8557_pwm_and_reg_pdata =;

static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata =;

/* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */

static const struct property_entry lenovo_yb1_x90_wacom_props[] =;

static const struct software_node lenovo_yb1_x90_wacom_node =;

/*
 * The HiDeep IST940E touchscreen comes up in I2C-HID mode. The native protocol
 * reports ABS_MT_PRESSURE and ABS_MT_TOUCH_MAJOR which are not reported in HID
 * mode, so using native mode is preferred.
 * It could alternatively be used in HID mode by changing the properties to:
 *	PROPERTY_ENTRY_U32("hid-descr-addr", 0x0020),
 *	PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
 * and changing board_info.type to "hid-over-i2c".
 */
static const struct property_entry lenovo_yb1_x90_hideep_ts_props[] =;

static const struct software_node lenovo_yb1_x90_hideep_ts_node =;

static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst =;

static const struct platform_device_info lenovo_yb1_x90_pdevs[] __initconst =;

/*
 * DSDT says UART path is "\\_SB.PCIO.URT1" with a letter 'O' instead of
 * the number '0' add the link manually.
 */
static const struct x86_serdev_info lenovo_yb1_x90_serdevs[] __initconst =;

static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst =;

static struct gpiod_lookup_table lenovo_yb1_x90_goodix_gpios =;

static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios =;

static struct gpiod_lookup_table lenovo_yb1_x90_wacom_gpios =;

static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] =;

static int __init lenovo_yb1_x90_init(struct device *dev)
{}

const struct x86_dev_info lenovo_yogabook_x90_info __initconst =;

/* Lenovo Yoga Book X91F/L Windows tablet needs manual instantiation of the fuel-gauge client */
static const struct x86_i2c_client_info lenovo_yogabook_x91_i2c_clients[] __initconst =;

const struct x86_dev_info lenovo_yogabook_x91_info __initconst =;

/* Lenovo Yoga Tablet 2 1050F/L's Android factory image has everything hardcoded */
static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] =;

static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node =;

static const struct x86_gpio_button lenovo_yoga_tab2_830_1050_lid __initconst =;

/* This gets filled by lenovo_yoga_tab2_830_1050_init() */
static struct rmi_device_platform_data lenovo_yoga_tab2_830_1050_rmi_pdata =;

static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initdata =;

static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios =;

#define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME

static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_codec_gpios =;

static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] =;

static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev);
static void lenovo_yoga_tab2_830_1050_exit(void);

const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst =;

/*
 * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same
 * mainboard, but the 830 uses a portrait LCD panel with a landscape touchscreen,
 * requiring the touchscreen driver to adjust the touch-coords to match the LCD.
 * And requiring the accelerometer to have a mount-matrix set to correct for
 * the 90° rotation of the LCD vs the frame.
 */
static const char * const lenovo_yoga_tab2_830_lms303d_mount_matrix[] =;

static const struct property_entry lenovo_yoga_tab2_830_lms303d_props[] =;

static const struct software_node lenovo_yoga_tab2_830_lms303d_node =;

static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
{}

/* SUS (INT33FC:02) pin 6 needs to be configured as pmu_clk for the audio codec */
static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =;

static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;

static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
{}

/*
 * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off()
 * gets used as pm_power_off handler. This causes "poweroff" on these tablets
 * to hang hard. Requiring pressing the power button for 30 seconds *twice*
 * followed by a normal 3 second press to recover. Avoid this by doing an EFI
 * poweroff instead.
 */
static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
{}

static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev)
{}

static void lenovo_yoga_tab2_830_1050_exit(void)
{}

/*
 * Lenovo Yoga Tablet 2 Pro 1380F/L
 *
 * The Lenovo Yoga Tablet 2 Pro 1380F/L mostly has the same design as the 830F/L
 * and the 1050F/L so this re-uses some of the handling for that from above.
 */
static const char * const lc824206xa_chg_det_psy[] =;

static const struct property_entry lenovo_yoga_tab2_1380_bq24190_props[] =;

static const struct software_node lenovo_yoga_tab2_1380_bq24190_node =;

/* For enabling the bq24190 5V boost based on id-pin */
static struct regulator_consumer_supply lc824206xa_consumer =;

static const struct regulator_init_data lenovo_yoga_tab2_1380_bq24190_vbus_init_data =;

struct bq24190_platform_data lenovo_yoga_tab2_1380_bq24190_pdata =;

static const struct property_entry lenovo_yoga_tab2_1380_lc824206xa_props[] =;

static const struct software_node lenovo_yoga_tab2_1380_lc824206xa_node =;

static const char * const lenovo_yoga_tab2_1380_lms303d_mount_matrix[] =;

static const struct property_entry lenovo_yoga_tab2_1380_lms303d_props[] =;

static const struct software_node lenovo_yoga_tab2_1380_lms303d_node =;

static const struct x86_i2c_client_info lenovo_yoga_tab2_1380_i2c_clients[] __initconst =;

static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initconst =;

const char * const lenovo_yoga_tab2_1380_modules[] __initconst =;

static int __init lenovo_yoga_tab2_1380_init(struct device *dev)
{}

static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios =;

static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] =;

const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst =;

/* Lenovo Yoga Tab 3 Pro YT3-X90F */

/*
 * There are 2 batteries, with 2 bq27500 fuel-gauges and 2 bq25892 chargers,
 * "bq25890-charger-1" is instantiated from: drivers/i2c/busses/i2c-cht-wc.c.
 */
static const char * const lenovo_yt3_bq25892_0_suppliers[] =;
static const char * const bq25890_1_psy[] =;

static const struct property_entry fg_bq25890_1_supply_props[] =;

static const struct software_node fg_bq25890_1_supply_node =;

/* bq25892 charger settings for the flat LiPo battery behind the screen */
static const struct property_entry lenovo_yt3_bq25892_0_props[] =;

static const struct software_node lenovo_yt3_bq25892_0_node =;

static const struct property_entry lenovo_yt3_hideep_ts_props[] =;

static const struct software_node lenovo_yt3_hideep_ts_node =;

static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst =;

/*
 * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
 * Function A Play/Pause:           0 ohm
 * Function D Voice assistant:    135 ohm
 * Function B Volume Up           240 ohm
 * Function C Volume Down         470 ohm
 * Minimum Mic DC resistance     1000 ohm
 * Minimum Ear speaker impedance   16 ohm
 * Note the first max value below must be less then the min. speaker impedance,
 * to allow CTIA/OMTP detection to work. The other max values are the closest
 * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
 */
static const struct arizona_micd_range arizona_micd_aosp_ranges[] =;

/* YT3 WM5102 arizona_micd_config comes from Android kernel sources */
static struct arizona_micd_config lenovo_yt3_wm5102_micd_config[] =;

static struct arizona_pdata lenovo_yt3_wm5102_pdata =;

static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst =;

static int __init lenovo_yt3_init(struct device *dev)
{}

static struct gpiod_lookup_table lenovo_yt3_hideep_gpios =;

static struct gpiod_lookup_table lenovo_yt3_wm5102_gpios =;

static struct gpiod_lookup_table * const lenovo_yt3_gpios[] =;

const struct x86_dev_info lenovo_yt3_info __initconst =;