diff mbox series

[3/5] platform/x86: x86-android-tablets: Add Lenovo Yoga Tablet 2 830 / 1050 data

Message ID 20220223133153.730337-4-hdegoede@redhat.com
State New
Headers show
Series pinctrl/baytrail platform/x86: SUS6 mux / Lenovo Yoga Tablet 2 support | expand

Commit Message

Hans de Goede Feb. 23, 2022, 1:31 p.m. UTC
The Lenovo Yoga Tablet 2 series comes in 4 versions: 830F, 830L, 1050F and
1050L. The F postfix indicates a wifi only version and the L postfix
indicates a LTE version. The 830 models are 8" and the 1050 models are 10".

Despite there being 8" and 10" versions all models use the same mainboard,
with an identical BIOS and thus identical DMI strings, so support for all
4 models is added through a single DMI table entry.

As all devices dealt with in the x86-android-tablets modules, these are
x86 ACPI tablets which ships with Android x86 as factory OS.
The mainboard's DSDT contain a bunch of I2C devices which are not actually
there, causing various resource conflicts. Enumeration of these is skipped
through the acpi_quirk_skip_i2c_client_enumeration().

Add support for manually instantiating the I2C devices which are
actually present on this tablet by adding the necessary device info to
the x86-android-tablets module.

This has been tested on a 830F and a 1050L tablet.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/platform/x86/x86-android-tablets.c | 184 +++++++++++++++++++++
 1 file changed, 184 insertions(+)

Comments

Andy Shevchenko Feb. 23, 2022, 3:04 p.m. UTC | #1
On Wed, Feb 23, 2022 at 02:31:51PM +0100, Hans de Goede wrote:
> The Lenovo Yoga Tablet 2 series comes in 4 versions: 830F, 830L, 1050F and
> 1050L. The F postfix indicates a wifi only version and the L postfix
> indicates a LTE version. The 830 models are 8" and the 1050 models are 10".
> 
> Despite there being 8" and 10" versions all models use the same mainboard,
> with an identical BIOS and thus identical DMI strings, so support for all
> 4 models is added through a single DMI table entry.
> 
> As all devices dealt with in the x86-android-tablets modules, these are
> x86 ACPI tablets which ships with Android x86 as factory OS.
> The mainboard's DSDT contain a bunch of I2C devices which are not actually
> there, causing various resource conflicts. Enumeration of these is skipped
> through the acpi_quirk_skip_i2c_client_enumeration().
> 
> Add support for manually instantiating the I2C devices which are
> actually present on this tablet by adding the necessary device info to
> the x86-android-tablets module.
> 
> This has been tested on a 830F and a 1050L tablet.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/platform/x86/x86-android-tablets.c | 184 +++++++++++++++++++++
>  1 file changed, 184 insertions(+)
> 
> diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c
> index 61e526e048c3..89972723f546 100644
> --- a/drivers/platform/x86/x86-android-tablets.c
> +++ b/drivers/platform/x86/x86-android-tablets.c
> @@ -22,8 +22,10 @@
>  #include <linux/irqdomain.h>
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
> +#include <linux/platform_data/lp855x.h>
>  #include <linux/platform_device.h>
>  #include <linux/power/bq24190_charger.h>
> +#include <linux/rmi.h>
>  #include <linux/serdev.h>
>  #include <linux/string.h>
>  /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
> @@ -182,6 +184,15 @@ static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" }
>  static const char * const bq24190_psy[] = { "bq24190-charger" };
>  static const char * const bq25890_psy[] = { "bq25890-charger" };
>  
> +static const struct property_entry fg_bq24190_supply_props[] = {
> +	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy),
> +	{ }
> +};
> +
> +static const struct software_node fg_bq24190_supply_node = {
> +	.properties = fg_bq24190_supply_props,
> +};
> +
>  static const struct property_entry fg_bq25890_supply_props[] = {
>  	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_psy),
>  	{ }
> @@ -704,6 +715,165 @@ static const struct x86_dev_info lenovo_yogabook_x9x_info __initconst = {
>  	.i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x9x_i2c_clients),
>  };
>  
> +/* Lenovo Yoga Tablet 2 1050F/L's Android factory img has everything hardcoded */
> +static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = {
> +	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", tusb1211_chg_det_psy),
> +	PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node),
> +	PROPERTY_ENTRY_BOOL("omit-battery-class"),
> +	PROPERTY_ENTRY_BOOL("disable-reset"),
> +	{ }
> +};
> +
> +static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node = {
> +	.properties = lenovo_yoga_tab2_830_1050_bq24190_props,
> +};
> +
> +/* 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 lp855x_platform_data lenovo_yoga_tab2_830_1050_lp8557_pdata = {
> +	.device_control = 0x86,
> +	.initial_brightness = 128,
> +};
> +
> +static const struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initconst = {
> +	{
> +		/* bq24292i battery charger */
> +		.board_info = {
> +			.type = "bq24190",
> +			.addr = 0x6b,
> +			.dev_name = "bq24292i",
> +			.swnode = &lenovo_yoga_tab2_830_1050_bq24190_node,
> +			.platform_data = &bq24190_pdata,
> +		},
> +		.adapter_path = "\\_SB_.I2C1",
> +		.irq_data = {
> +			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
> +			.chip = "INT33FC:02",
> +			.index = 2,
> +			.trigger = ACPI_EDGE_SENSITIVE,
> +			.polarity = ACPI_ACTIVE_HIGH,
> +		},
> +	}, {
> +		/* BQ27541 fuel-gauge */
> +		.board_info = {
> +			.type = "bq27541",
> +			.addr = 0x55,
> +			.dev_name = "bq27541",
> +			.swnode = &fg_bq24190_supply_node,
> +		},
> +		.adapter_path = "\\_SB_.I2C1",
> +	}, {
> +		/* Synaptics RMI touchscreen */
> +		.board_info = {
> +			.type = "rmi4_i2c",
> +			.addr = 0x38,
> +			.dev_name = "rmi4_i2c",
> +			.platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata,
> +		},
> +		.adapter_path = "\\_SB_.I2C6",
> +		.irq_data = {
> +			.type = X86_ACPI_IRQ_TYPE_APIC,
> +			.index = 0x45,
> +			.trigger = ACPI_EDGE_SENSITIVE,
> +			.polarity = ACPI_ACTIVE_HIGH,
> +		},
> +	}, {
> +		/* LP8557 Backlight controller */
> +		.board_info = {
> +			.type = "lp8557",
> +			.addr = 0x2c,
> +			.dev_name = "lp8557",
> +			.platform_data = &lenovo_yoga_tab2_830_1050_lp8557_pdata,
> +		},
> +		.adapter_path = "\\_SB_.I2C3",
> +	},
> +};
> +
> +static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios = {
> +	.dev_id = "intel-int3496",
> +	.table = {
> +		GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_LOW),
> +		GPIO_LOOKUP("INT33FC:02", 24, "id", GPIO_ACTIVE_HIGH),
> +		{ }
> +	},
> +};
> +
> +static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = {
> +	&lenovo_yoga_tab2_830_1050_int3496_gpios,
> +	NULL
> +};
> +
> +static int __init lenovo_yoga_tab2_830_1050_init(void);
> +static void lenovo_yoga_tab2_830_1050_exit(void);
> +
> +static struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initdata = {
> +	.i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients,
> +	/* i2c_client_count gets set by lenovo_yoga_tab2_830_1050_init() */
> +	.pdev_info = int3496_pdevs,
> +	.pdev_count = ARRAY_SIZE(int3496_pdevs),
> +	.gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios,
> +	.bat_swnode = &generic_lipo_hv_4v35_battery_node,
> +	.modules = bq24190_modules,
> +	.invalid_aei_gpiochip = "INT33FC:02",
> +	.init = lenovo_yoga_tab2_830_1050_init,
> +};
> +
> +/*
> + * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same
> + * mainboard, but they need some different treatment related to the display:
> + * 1. The 830 uses a portrait LCD panel with a landscape touchscreen, requiring
> + *    the touchscreen driver to adjust the touch-coords to match the LCD.
> + * 2. Both use an TI LP8557 LED backlight controller. On the 1050 the LP8557's
> + *    PWM input is connected to the PMIC's PWM output and everything works fine
> + *    with the defaults programmed into the LP8557 by the BIOS.
> + *    But on the 830 the LP8557's PWM input is connected to a PWM output coming
> + *    from the LCD panel's controller. The Android code has a hack in the i915
> + *    driver to write the non-standard DSI reg 0x9f with the desired backlight
> + *    level to set the duty-cycle of the LCD's PWM output.
> + *
> + *    To avoid having to have a similar hack in the mainline kernel the LP8557
> + *    entry in lenovo_yoga_tab2_830_1050_i2c_clients instead just programs the
> + *    LP8557 to directly set the level, ignoring the PWM input. This means that
> + *    the LP8557 i2c_client should only be instantiated on the 830.
> + */
> +static int __init lenovo_yoga_tab2_830_1050_init_display(void)
> +{
> +	struct gpio_desc *gpiod;
> +	int ret;
> +
> +	/* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
> +	ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, &gpiod);
> +	if (ret)
> +		return ret;
> +
> +	ret = gpiod_get_value_cansleep(gpiod);
> +	if (ret) {
> +		pr_info("detected Lenovo Yoga Tablet 2 1050F/L\n");
> +		lenovo_yoga_tab2_830_1050_info.i2c_client_count =
> +			ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients) - 1;
> +	} else {
> +		pr_info("detected Lenovo Yoga Tablet 2 830F/L\n");
> +		lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.swap_axes = true;
> +		lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.flip_y = true;
> +		lenovo_yoga_tab2_830_1050_info.i2c_client_count =
> +			ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients);
> +	}
> +
> +	return 0;
> +}
> +
> +static int __init lenovo_yoga_tab2_830_1050_init(void)
> +{
> +	int ret;
> +
> +	ret = lenovo_yoga_tab2_830_1050_init_display();
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
>  /* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */
>  static const char * const nextbook_ares8_accel_mount_matrix[] = {
>  	"0", "-1", "0",
> @@ -948,6 +1118,20 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
>  		},
>  		.driver_data = (void *)&lenovo_yogabook_x9x_info,
>  	},
> +	{
> +		/*
> +		 * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10"
> +		 * Lenovo Yoga Tablet 2 use the same mainboard)
> +		 */
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
> +			DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
> +			DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
> +			/* Partial match on beginning of BIOS version */
> +			DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
> +		},
> +		.driver_data = (void *)&lenovo_yoga_tab2_830_1050_info,
> +	},
>  	{
>  		/* Nextbook Ares 8 */
>  		.matches = {
> -- 
> 2.35.1
>
diff mbox series

Patch

diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c
index 61e526e048c3..89972723f546 100644
--- a/drivers/platform/x86/x86-android-tablets.c
+++ b/drivers/platform/x86/x86-android-tablets.c
@@ -22,8 +22,10 @@ 
 #include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/platform_data/lp855x.h>
 #include <linux/platform_device.h>
 #include <linux/power/bq24190_charger.h>
+#include <linux/rmi.h>
 #include <linux/serdev.h>
 #include <linux/string.h>
 /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
@@ -182,6 +184,15 @@  static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" }
 static const char * const bq24190_psy[] = { "bq24190-charger" };
 static const char * const bq25890_psy[] = { "bq25890-charger" };
 
+static const struct property_entry fg_bq24190_supply_props[] = {
+	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy),
+	{ }
+};
+
+static const struct software_node fg_bq24190_supply_node = {
+	.properties = fg_bq24190_supply_props,
+};
+
 static const struct property_entry fg_bq25890_supply_props[] = {
 	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_psy),
 	{ }
@@ -704,6 +715,165 @@  static const struct x86_dev_info lenovo_yogabook_x9x_info __initconst = {
 	.i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x9x_i2c_clients),
 };
 
+/* Lenovo Yoga Tablet 2 1050F/L's Android factory img has everything hardcoded */
+static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = {
+	PROPERTY_ENTRY_STRING_ARRAY("supplied-from", tusb1211_chg_det_psy),
+	PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node),
+	PROPERTY_ENTRY_BOOL("omit-battery-class"),
+	PROPERTY_ENTRY_BOOL("disable-reset"),
+	{ }
+};
+
+static const struct software_node lenovo_yoga_tab2_830_1050_bq24190_node = {
+	.properties = lenovo_yoga_tab2_830_1050_bq24190_props,
+};
+
+/* 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 lp855x_platform_data lenovo_yoga_tab2_830_1050_lp8557_pdata = {
+	.device_control = 0x86,
+	.initial_brightness = 128,
+};
+
+static const struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initconst = {
+	{
+		/* bq24292i battery charger */
+		.board_info = {
+			.type = "bq24190",
+			.addr = 0x6b,
+			.dev_name = "bq24292i",
+			.swnode = &lenovo_yoga_tab2_830_1050_bq24190_node,
+			.platform_data = &bq24190_pdata,
+		},
+		.adapter_path = "\\_SB_.I2C1",
+		.irq_data = {
+			.type = X86_ACPI_IRQ_TYPE_GPIOINT,
+			.chip = "INT33FC:02",
+			.index = 2,
+			.trigger = ACPI_EDGE_SENSITIVE,
+			.polarity = ACPI_ACTIVE_HIGH,
+		},
+	}, {
+		/* BQ27541 fuel-gauge */
+		.board_info = {
+			.type = "bq27541",
+			.addr = 0x55,
+			.dev_name = "bq27541",
+			.swnode = &fg_bq24190_supply_node,
+		},
+		.adapter_path = "\\_SB_.I2C1",
+	}, {
+		/* Synaptics RMI touchscreen */
+		.board_info = {
+			.type = "rmi4_i2c",
+			.addr = 0x38,
+			.dev_name = "rmi4_i2c",
+			.platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata,
+		},
+		.adapter_path = "\\_SB_.I2C6",
+		.irq_data = {
+			.type = X86_ACPI_IRQ_TYPE_APIC,
+			.index = 0x45,
+			.trigger = ACPI_EDGE_SENSITIVE,
+			.polarity = ACPI_ACTIVE_HIGH,
+		},
+	}, {
+		/* LP8557 Backlight controller */
+		.board_info = {
+			.type = "lp8557",
+			.addr = 0x2c,
+			.dev_name = "lp8557",
+			.platform_data = &lenovo_yoga_tab2_830_1050_lp8557_pdata,
+		},
+		.adapter_path = "\\_SB_.I2C3",
+	},
+};
+
+static struct gpiod_lookup_table lenovo_yoga_tab2_830_1050_int3496_gpios = {
+	.dev_id = "intel-int3496",
+	.table = {
+		GPIO_LOOKUP("INT33FC:02", 1, "mux", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("INT33FC:02", 24, "id", GPIO_ACTIVE_HIGH),
+		{ }
+	},
+};
+
+static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = {
+	&lenovo_yoga_tab2_830_1050_int3496_gpios,
+	NULL
+};
+
+static int __init lenovo_yoga_tab2_830_1050_init(void);
+static void lenovo_yoga_tab2_830_1050_exit(void);
+
+static struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initdata = {
+	.i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients,
+	/* i2c_client_count gets set by lenovo_yoga_tab2_830_1050_init() */
+	.pdev_info = int3496_pdevs,
+	.pdev_count = ARRAY_SIZE(int3496_pdevs),
+	.gpiod_lookup_tables = lenovo_yoga_tab2_830_1050_gpios,
+	.bat_swnode = &generic_lipo_hv_4v35_battery_node,
+	.modules = bq24190_modules,
+	.invalid_aei_gpiochip = "INT33FC:02",
+	.init = lenovo_yoga_tab2_830_1050_init,
+};
+
+/*
+ * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same
+ * mainboard, but they need some different treatment related to the display:
+ * 1. The 830 uses a portrait LCD panel with a landscape touchscreen, requiring
+ *    the touchscreen driver to adjust the touch-coords to match the LCD.
+ * 2. Both use an TI LP8557 LED backlight controller. On the 1050 the LP8557's
+ *    PWM input is connected to the PMIC's PWM output and everything works fine
+ *    with the defaults programmed into the LP8557 by the BIOS.
+ *    But on the 830 the LP8557's PWM input is connected to a PWM output coming
+ *    from the LCD panel's controller. The Android code has a hack in the i915
+ *    driver to write the non-standard DSI reg 0x9f with the desired backlight
+ *    level to set the duty-cycle of the LCD's PWM output.
+ *
+ *    To avoid having to have a similar hack in the mainline kernel the LP8557
+ *    entry in lenovo_yoga_tab2_830_1050_i2c_clients instead just programs the
+ *    LP8557 to directly set the level, ignoring the PWM input. This means that
+ *    the LP8557 i2c_client should only be instantiated on the 830.
+ */
+static int __init lenovo_yoga_tab2_830_1050_init_display(void)
+{
+	struct gpio_desc *gpiod;
+	int ret;
+
+	/* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
+	ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, &gpiod);
+	if (ret)
+		return ret;
+
+	ret = gpiod_get_value_cansleep(gpiod);
+	if (ret) {
+		pr_info("detected Lenovo Yoga Tablet 2 1050F/L\n");
+		lenovo_yoga_tab2_830_1050_info.i2c_client_count =
+			ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients) - 1;
+	} else {
+		pr_info("detected Lenovo Yoga Tablet 2 830F/L\n");
+		lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.swap_axes = true;
+		lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.flip_y = true;
+		lenovo_yoga_tab2_830_1050_info.i2c_client_count =
+			ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients);
+	}
+
+	return 0;
+}
+
+static int __init lenovo_yoga_tab2_830_1050_init(void)
+{
+	int ret;
+
+	ret = lenovo_yoga_tab2_830_1050_init_display();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 /* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */
 static const char * const nextbook_ares8_accel_mount_matrix[] = {
 	"0", "-1", "0",
@@ -948,6 +1118,20 @@  static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
 		},
 		.driver_data = (void *)&lenovo_yogabook_x9x_info,
 	},
+	{
+		/*
+		 * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10"
+		 * Lenovo Yoga Tablet 2 use the same mainboard)
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
+			DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
+			/* Partial match on beginning of BIOS version */
+			DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
+		},
+		.driver_data = (void *)&lenovo_yoga_tab2_830_1050_info,
+	},
 	{
 		/* Nextbook Ares 8 */
 		.matches = {