platform/x86: x86-android-tablets: convert Goodix devices to GPIO references

Now that gpiolib supports software nodes to describe GPIOs, switch the
driver away from using GPIO lookup tables for Goodix touchscreens to
using PROPERTY_ENTRY_GPIO() to keep all touchscreen properties together.

Since the tablets are using either Baytrail or Cherryview GPIO
controllers x86_dev_info structure has been extended to carry gpiochip
type information so that the code can instantiate correct set of
software nodes representing the GPIO chip.

Because this adds a new point of failure in x86_android_tablet_probe(),
x86_android_tablet_remove() is rearranged to handle cases where battery
swnode has not been registered yet, and registering of GPIO lookup
tables is moved earlier as it can not fail.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Tested-by: Hans de Goede <hansg@kernel.org>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hansg@kernel.org>
Link: https://patch.msgid.link/20250920200713.20193-2-hansg@kernel.org
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
Dmitry Torokhov
2025-09-20 22:06:54 +02:00
committed by Ilpo Järvinen
parent e3b1320be6
commit b40088bfdb
5 changed files with 105 additions and 58 deletions

View File

@@ -9,6 +9,7 @@
*/
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/input.h>
#include <linux/platform_device.h>
@@ -77,6 +78,16 @@ static const struct software_node asus_me176c_ug3105_node = {
.properties = asus_me176c_ug3105_props,
};
static const struct property_entry asus_me176c_touchscreen_props[] = {
PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[0], 60, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 28, GPIO_ACTIVE_HIGH),
{ }
};
static const struct software_node asus_me176c_touchscreen_node = {
.properties = asus_me176c_touchscreen_props,
};
static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst = {
{
/* bq24297 battery charger */
@@ -132,6 +143,7 @@ static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst =
.type = "GDIX1001:00",
.addr = 0x14,
.dev_name = "goodix_ts",
.swnode = &asus_me176c_touchscreen_node,
},
.adapter_path = "\\_SB_.I2C6",
.irq_data = {
@@ -152,18 +164,8 @@ static const struct x86_serdev_info asus_me176c_serdevs[] __initconst = {
},
};
static struct gpiod_lookup_table asus_me176c_goodix_gpios = {
.dev_id = "i2c-goodix_ts",
.table = {
GPIO_LOOKUP("INT33FC:00", 60, "reset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("INT33FC:02", 28, "irq", GPIO_ACTIVE_HIGH),
{ }
},
};
static struct gpiod_lookup_table * const asus_me176c_gpios[] = {
&int3496_gpo2_pin22_gpios,
&asus_me176c_goodix_gpios,
NULL
};
@@ -179,6 +181,7 @@ const struct x86_dev_info asus_me176c_info __initconst = {
.gpiod_lookup_tables = asus_me176c_gpios,
.bat_swnode = &generic_lipo_hv_4v35_battery_node,
.modules = bq24190_modules,
.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
};
/* Asus TF103C tablets have an Android factory image with everything hardcoded */

View File

@@ -155,6 +155,7 @@ static struct serdev_device **serdevs;
static struct gpio_keys_button *buttons;
static struct gpiod_lookup_table * const *gpiod_lookup_tables;
static const struct software_node *bat_swnode;
static const struct software_node **gpiochip_node_group;
static void (*exit_handler)(void);
static __init struct i2c_adapter *
@@ -330,6 +331,34 @@ static __init int x86_instantiate_serdev(const struct x86_dev_info *dev_info, in
return ret;
}
const struct software_node baytrail_gpiochip_nodes[] = {
{ .name = "INT33FC:00" },
{ .name = "INT33FC:01" },
{ .name = "INT33FC:02" },
};
static const struct software_node *baytrail_gpiochip_node_group[] = {
&baytrail_gpiochip_nodes[0],
&baytrail_gpiochip_nodes[1],
&baytrail_gpiochip_nodes[2],
NULL
};
const struct software_node cherryview_gpiochip_nodes[] = {
{ .name = "INT33FF:00" },
{ .name = "INT33FF:01" },
{ .name = "INT33FF:02" },
{ .name = "INT33FF:03" },
};
static const struct software_node *cherryview_gpiochip_node_group[] = {
&cherryview_gpiochip_nodes[0],
&cherryview_gpiochip_nodes[1],
&cherryview_gpiochip_nodes[2],
&cherryview_gpiochip_nodes[3],
NULL
};
static void x86_android_tablet_remove(struct platform_device *pdev)
{
int i;
@@ -360,10 +389,14 @@ static void x86_android_tablet_remove(struct platform_device *pdev)
if (exit_handler)
exit_handler();
if (bat_swnode)
software_node_unregister(bat_swnode);
if (gpiochip_node_group)
software_node_unregister_node_group(gpiochip_node_group);
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
software_node_unregister(bat_swnode);
}
static __init int x86_android_tablet_probe(struct platform_device *pdev)
@@ -387,16 +420,36 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev)
for (i = 0; dev_info->modules && dev_info->modules[i]; i++)
request_module(dev_info->modules[i]);
bat_swnode = dev_info->bat_swnode;
if (bat_swnode) {
ret = software_node_register(bat_swnode);
gpiod_lookup_tables = dev_info->gpiod_lookup_tables;
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
gpiod_add_lookup_table(gpiod_lookup_tables[i]);
switch (dev_info->gpiochip_type) {
case X86_GPIOCHIP_BAYTRAIL:
gpiochip_node_group = baytrail_gpiochip_node_group;
break;
case X86_GPIOCHIP_CHERRYVIEW:
gpiochip_node_group = cherryview_gpiochip_node_group;
break;
case X86_GPIOCHIP_UNSPECIFIED:
gpiochip_node_group = NULL;
break;
}
if (gpiochip_node_group) {
ret = software_node_register_node_group(gpiochip_node_group);
if (ret)
return ret;
}
gpiod_lookup_tables = dev_info->gpiod_lookup_tables;
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
gpiod_add_lookup_table(gpiod_lookup_tables[i]);
if (dev_info->bat_swnode) {
ret = software_node_register(dev_info->bat_swnode);
if (ret) {
x86_android_tablet_remove(pdev);
return ret;
}
bat_swnode = dev_info->bat_swnode;
}
if (dev_info->init) {
ret = dev_info->init(&pdev->dev);

View File

@@ -12,6 +12,7 @@
#include <linux/efi.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h>
#include <linux/mfd/intel_soc_pmic.h>
@@ -61,6 +62,16 @@ 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_goodix_props[] = {
PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[1], 53, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_GPIO("irq-gpios", &cherryview_gpiochip_nodes[1], 56, GPIO_ACTIVE_HIGH),
{ }
};
static const struct software_node lenovo_yb1_x90_goodix_node = {
.properties = lenovo_yb1_x90_goodix_props,
};
static const struct property_entry lenovo_yb1_x90_wacom_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001),
PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 150),
@@ -108,6 +119,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.type = "GDIX1001:00",
.addr = 0x14,
.dev_name = "goodix_ts",
.swnode = &lenovo_yb1_x90_goodix_node,
},
.adapter_path = "\\_SB_.PCI0.I2C2",
.irq_data = {
@@ -198,15 +210,6 @@ static const struct x86_gpio_button lenovo_yb1_x90_lid __initconst = {
.pin = 19,
};
static struct gpiod_lookup_table lenovo_yb1_x90_goodix_gpios = {
.dev_id = "i2c-goodix_ts",
.table = {
GPIO_LOOKUP("INT33FF:01", 53, "reset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("INT33FF:01", 56, "irq", GPIO_ACTIVE_HIGH),
{ }
},
};
static struct gpiod_lookup_table lenovo_yb1_x90_hideep_gpios = {
.dev_id = "i2c-hideep_ts",
.table = {
@@ -225,7 +228,6 @@ static struct gpiod_lookup_table lenovo_yb1_x90_wacom_gpios = {
static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = {
&lenovo_yb1_x90_hideep_gpios,
&lenovo_yb1_x90_goodix_gpios,
&lenovo_yb1_x90_wacom_gpios,
NULL
};
@@ -259,6 +261,7 @@ const struct x86_dev_info lenovo_yogabook_x90_info __initconst = {
.gpio_button = &lenovo_yb1_x90_lid,
.gpio_button_count = 1,
.gpiod_lookup_tables = lenovo_yb1_x90_gpios,
.gpiochip_type = X86_GPIOCHIP_CHERRYVIEW,
.init = lenovo_yb1_x90_init,
};

View File

@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/pci.h>
@@ -297,6 +298,8 @@ static const struct software_node medion_lifetab_s10346_accel_node = {
static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH),
{ }
};
@@ -340,24 +343,10 @@ static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __in
},
};
static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
.dev_id = "i2c-goodix_ts",
.table = {
GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
{ }
},
};
static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
&medion_lifetab_s10346_goodix_gpios,
NULL
};
const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
.i2c_client_info = medion_lifetab_s10346_i2c_clients,
.i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
.gpiod_lookup_tables = medion_lifetab_s10346_gpios,
.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
};
/* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
@@ -543,6 +532,8 @@ static const struct property_entry whitelabel_tm800a550l_goodix_props[] = {
PROPERTY_ENTRY_STRING("firmware-name", "gt912-tm800a550l.fw"),
PROPERTY_ENTRY_STRING("goodix,config-name", "gt912-tm800a550l.cfg"),
PROPERTY_ENTRY_U32("goodix,main-clk", 54),
PROPERTY_ENTRY_GPIO("reset-gpios", &baytrail_gpiochip_nodes[1], 26, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_GPIO("irq-gpios", &baytrail_gpiochip_nodes[2], 3, GPIO_ACTIVE_HIGH),
{ }
};
@@ -578,24 +569,10 @@ static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __in
},
};
static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
.dev_id = "i2c-goodix_ts",
.table = {
GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
{ }
},
};
static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
&whitelabel_tm800a550l_goodix_gpios,
NULL
};
const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
.i2c_client_info = whitelabel_tm800a550l_i2c_clients,
.i2c_client_count = ARRAY_SIZE(whitelabel_tm800a550l_i2c_clients),
.gpiod_lookup_tables = whitelabel_tm800a550l_gpios,
.gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
};
/*

View File

@@ -32,6 +32,12 @@ enum x86_acpi_irq_type {
X86_ACPI_IRQ_TYPE_PMIC,
};
enum x86_gpiochip_type {
X86_GPIOCHIP_UNSPECIFIED = 0,
X86_GPIOCHIP_BAYTRAIL,
X86_GPIOCHIP_CHERRYVIEW,
};
struct x86_acpi_irq_data {
char *chip; /* GPIO chip label (GPIOINT) or PMIC ACPI path (PMIC) */
enum x86_acpi_irq_type type;
@@ -99,6 +105,7 @@ struct x86_dev_info {
int (*init)(struct device *dev);
void (*exit)(void);
bool use_pci;
enum x86_gpiochip_type gpiochip_type;
};
int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
@@ -106,6 +113,10 @@ int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
struct gpio_desc **desc);
int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data);
/* Software nodes representing GPIO chips used by various tablets */
extern const struct software_node baytrail_gpiochip_nodes[];
extern const struct software_node cherryview_gpiochip_nodes[];
/*
* Extern declarations of x86_dev_info structs so there can be a single
* MODULE_DEVICE_TABLE(dmi, ...), while splitting the board descriptions.