18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Driver for Goodix Touchscreens
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (c) 2014 Red Hat Inc.
68c2ecf20Sopenharmony_ci *  Copyright (c) 2015 K. Merker <merker@debian.org>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci *  This code is based on gt9xx.c authored by andrew@goodix.com:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  2010 - 2012 Goodix Technology.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/dmi.h>
168c2ecf20Sopenharmony_ci#include <linux/firmware.h>
178c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
188c2ecf20Sopenharmony_ci#include <linux/i2c.h>
198c2ecf20Sopenharmony_ci#include <linux/input.h>
208c2ecf20Sopenharmony_ci#include <linux/input/mt.h>
218c2ecf20Sopenharmony_ci#include <linux/input/touchscreen.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/delay.h>
248c2ecf20Sopenharmony_ci#include <linux/irq.h>
258c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
268c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <linux/acpi.h>
298c2ecf20Sopenharmony_ci#include <linux/of.h>
308c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define GOODIX_GPIO_INT_NAME		"irq"
338c2ecf20Sopenharmony_ci#define GOODIX_GPIO_RST_NAME		"reset"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define GOODIX_MAX_HEIGHT		4096
368c2ecf20Sopenharmony_ci#define GOODIX_MAX_WIDTH		4096
378c2ecf20Sopenharmony_ci#define GOODIX_INT_TRIGGER		1
388c2ecf20Sopenharmony_ci#define GOODIX_CONTACT_SIZE		8
398c2ecf20Sopenharmony_ci#define GOODIX_MAX_CONTACT_SIZE		9
408c2ecf20Sopenharmony_ci#define GOODIX_MAX_CONTACTS		10
418c2ecf20Sopenharmony_ci#define GOODIX_MAX_KEYS			7
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_MIN_LENGTH	186
448c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_911_LENGTH	186
458c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_967_LENGTH	228
468c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_GT9X_LENGTH	240
478c2ecf20Sopenharmony_ci#define GOODIX_CONFIG_MAX_LENGTH	240
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/* Register defines */
508c2ecf20Sopenharmony_ci#define GOODIX_REG_COMMAND		0x8040
518c2ecf20Sopenharmony_ci#define GOODIX_CMD_SCREEN_OFF		0x05
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define GOODIX_READ_COOR_ADDR		0x814E
548c2ecf20Sopenharmony_ci#define GOODIX_GT1X_REG_CONFIG_DATA	0x8050
558c2ecf20Sopenharmony_ci#define GOODIX_GT9X_REG_CONFIG_DATA	0x8047
568c2ecf20Sopenharmony_ci#define GOODIX_REG_ID			0x8140
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define GOODIX_BUFFER_STATUS_READY	BIT(7)
598c2ecf20Sopenharmony_ci#define GOODIX_HAVE_KEY			BIT(4)
608c2ecf20Sopenharmony_ci#define GOODIX_BUFFER_STATUS_TIMEOUT	20
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define RESOLUTION_LOC		1
638c2ecf20Sopenharmony_ci#define MAX_CONTACTS_LOC	5
648c2ecf20Sopenharmony_ci#define TRIGGER_LOC		6
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* Our special handling for GPIO accesses through ACPI is x86 specific */
678c2ecf20Sopenharmony_ci#if defined CONFIG_X86 && defined CONFIG_ACPI
688c2ecf20Sopenharmony_ci#define ACPI_GPIO_SUPPORT
698c2ecf20Sopenharmony_ci#endif
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct goodix_ts_data;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cienum goodix_irq_pin_access_method {
748c2ecf20Sopenharmony_ci	IRQ_PIN_ACCESS_NONE,
758c2ecf20Sopenharmony_ci	IRQ_PIN_ACCESS_GPIO,
768c2ecf20Sopenharmony_ci	IRQ_PIN_ACCESS_ACPI_GPIO,
778c2ecf20Sopenharmony_ci	IRQ_PIN_ACCESS_ACPI_METHOD,
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistruct goodix_chip_data {
818c2ecf20Sopenharmony_ci	u16 config_addr;
828c2ecf20Sopenharmony_ci	int config_len;
838c2ecf20Sopenharmony_ci	int (*check_config)(struct goodix_ts_data *ts, const u8 *cfg, int len);
848c2ecf20Sopenharmony_ci	void (*calc_config_checksum)(struct goodix_ts_data *ts);
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct goodix_chip_id {
888c2ecf20Sopenharmony_ci	const char *id;
898c2ecf20Sopenharmony_ci	const struct goodix_chip_data *data;
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define GOODIX_ID_MAX_LEN	4
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistruct goodix_ts_data {
958c2ecf20Sopenharmony_ci	struct i2c_client *client;
968c2ecf20Sopenharmony_ci	struct input_dev *input_dev;
978c2ecf20Sopenharmony_ci	const struct goodix_chip_data *chip;
988c2ecf20Sopenharmony_ci	struct touchscreen_properties prop;
998c2ecf20Sopenharmony_ci	unsigned int max_touch_num;
1008c2ecf20Sopenharmony_ci	unsigned int int_trigger_type;
1018c2ecf20Sopenharmony_ci	struct regulator *avdd28;
1028c2ecf20Sopenharmony_ci	struct regulator *vddio;
1038c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_int;
1048c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod_rst;
1058c2ecf20Sopenharmony_ci	int gpio_count;
1068c2ecf20Sopenharmony_ci	int gpio_int_idx;
1078c2ecf20Sopenharmony_ci	char id[GOODIX_ID_MAX_LEN + 1];
1088c2ecf20Sopenharmony_ci	u16 version;
1098c2ecf20Sopenharmony_ci	const char *cfg_name;
1108c2ecf20Sopenharmony_ci	bool reset_controller_at_probe;
1118c2ecf20Sopenharmony_ci	bool load_cfg_from_disk;
1128c2ecf20Sopenharmony_ci	struct completion firmware_loading_complete;
1138c2ecf20Sopenharmony_ci	unsigned long irq_flags;
1148c2ecf20Sopenharmony_ci	enum goodix_irq_pin_access_method irq_pin_access_method;
1158c2ecf20Sopenharmony_ci	unsigned int contact_size;
1168c2ecf20Sopenharmony_ci	u8 config[GOODIX_CONFIG_MAX_LENGTH];
1178c2ecf20Sopenharmony_ci	unsigned short keymap[GOODIX_MAX_KEYS];
1188c2ecf20Sopenharmony_ci};
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts,
1218c2ecf20Sopenharmony_ci			      const u8 *cfg, int len);
1228c2ecf20Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts,
1238c2ecf20Sopenharmony_ci			       const u8 *cfg, int len);
1248c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts);
1258c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt1x_chip_data = {
1288c2ecf20Sopenharmony_ci	.config_addr		= GOODIX_GT1X_REG_CONFIG_DATA,
1298c2ecf20Sopenharmony_ci	.config_len		= GOODIX_CONFIG_GT9X_LENGTH,
1308c2ecf20Sopenharmony_ci	.check_config		= goodix_check_cfg_16,
1318c2ecf20Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_16,
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt911_chip_data = {
1358c2ecf20Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
1368c2ecf20Sopenharmony_ci	.config_len		= GOODIX_CONFIG_911_LENGTH,
1378c2ecf20Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
1388c2ecf20Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt967_chip_data = {
1428c2ecf20Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
1438c2ecf20Sopenharmony_ci	.config_len		= GOODIX_CONFIG_967_LENGTH,
1448c2ecf20Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
1458c2ecf20Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
1468c2ecf20Sopenharmony_ci};
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic const struct goodix_chip_data gt9x_chip_data = {
1498c2ecf20Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
1508c2ecf20Sopenharmony_ci	.config_len		= GOODIX_CONFIG_GT9X_LENGTH,
1518c2ecf20Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
1528c2ecf20Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic const struct goodix_chip_id goodix_chip_ids[] = {
1568c2ecf20Sopenharmony_ci	{ .id = "1151", .data = &gt1x_chip_data },
1578c2ecf20Sopenharmony_ci	{ .id = "1158", .data = &gt1x_chip_data },
1588c2ecf20Sopenharmony_ci	{ .id = "5663", .data = &gt1x_chip_data },
1598c2ecf20Sopenharmony_ci	{ .id = "5688", .data = &gt1x_chip_data },
1608c2ecf20Sopenharmony_ci	{ .id = "917S", .data = &gt1x_chip_data },
1618c2ecf20Sopenharmony_ci	{ .id = "9286", .data = &gt1x_chip_data },
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	{ .id = "911", .data = &gt911_chip_data },
1648c2ecf20Sopenharmony_ci	{ .id = "9271", .data = &gt911_chip_data },
1658c2ecf20Sopenharmony_ci	{ .id = "9110", .data = &gt911_chip_data },
1668c2ecf20Sopenharmony_ci	{ .id = "9111", .data = &gt911_chip_data },
1678c2ecf20Sopenharmony_ci	{ .id = "927", .data = &gt911_chip_data },
1688c2ecf20Sopenharmony_ci	{ .id = "928", .data = &gt911_chip_data },
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	{ .id = "912", .data = &gt967_chip_data },
1718c2ecf20Sopenharmony_ci	{ .id = "9147", .data = &gt967_chip_data },
1728c2ecf20Sopenharmony_ci	{ .id = "967", .data = &gt967_chip_data },
1738c2ecf20Sopenharmony_ci	{ }
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic const unsigned long goodix_irq_flags[] = {
1778c2ecf20Sopenharmony_ci	IRQ_TYPE_EDGE_RISING,
1788c2ecf20Sopenharmony_ci	IRQ_TYPE_EDGE_FALLING,
1798c2ecf20Sopenharmony_ci	IRQ_TYPE_LEVEL_LOW,
1808c2ecf20Sopenharmony_ci	IRQ_TYPE_LEVEL_HIGH,
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic const struct dmi_system_id nine_bytes_report[] = {
1848c2ecf20Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86)
1858c2ecf20Sopenharmony_ci	{
1868c2ecf20Sopenharmony_ci		/* Lenovo Yoga Book X90F / X90L */
1878c2ecf20Sopenharmony_ci		.matches = {
1888c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
1898c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
1908c2ecf20Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci	},
1938c2ecf20Sopenharmony_ci	{
1948c2ecf20Sopenharmony_ci		/* Lenovo Yoga Book X91F / X91L */
1958c2ecf20Sopenharmony_ci		.matches = {
1968c2ecf20Sopenharmony_ci			/* Non exact match to match F + L versions */
1978c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
1988c2ecf20Sopenharmony_ci		}
1998c2ecf20Sopenharmony_ci	},
2008c2ecf20Sopenharmony_ci#endif
2018c2ecf20Sopenharmony_ci	{}
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/*
2058c2ecf20Sopenharmony_ci * Those tablets have their x coordinate inverted
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_cistatic const struct dmi_system_id inverted_x_screen[] = {
2088c2ecf20Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86)
2098c2ecf20Sopenharmony_ci	{
2108c2ecf20Sopenharmony_ci		.ident = "Cube I15-TC",
2118c2ecf20Sopenharmony_ci		.matches = {
2128c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Cube"),
2138c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC")
2148c2ecf20Sopenharmony_ci		},
2158c2ecf20Sopenharmony_ci	},
2168c2ecf20Sopenharmony_ci#endif
2178c2ecf20Sopenharmony_ci	{}
2188c2ecf20Sopenharmony_ci};
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci/**
2218c2ecf20Sopenharmony_ci * goodix_i2c_read - read data from a register of the i2c slave device.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * @client: i2c device.
2248c2ecf20Sopenharmony_ci * @reg: the register to read from.
2258c2ecf20Sopenharmony_ci * @buf: raw write data buffer.
2268c2ecf20Sopenharmony_ci * @len: length of the buffer to write
2278c2ecf20Sopenharmony_ci */
2288c2ecf20Sopenharmony_cistatic int goodix_i2c_read(struct i2c_client *client,
2298c2ecf20Sopenharmony_ci			   u16 reg, u8 *buf, int len)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2];
2328c2ecf20Sopenharmony_ci	__be16 wbuf = cpu_to_be16(reg);
2338c2ecf20Sopenharmony_ci	int ret;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	msgs[0].flags = 0;
2368c2ecf20Sopenharmony_ci	msgs[0].addr  = client->addr;
2378c2ecf20Sopenharmony_ci	msgs[0].len   = 2;
2388c2ecf20Sopenharmony_ci	msgs[0].buf   = (u8 *)&wbuf;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	msgs[1].flags = I2C_M_RD;
2418c2ecf20Sopenharmony_ci	msgs[1].addr  = client->addr;
2428c2ecf20Sopenharmony_ci	msgs[1].len   = len;
2438c2ecf20Sopenharmony_ci	msgs[1].buf   = buf;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, 2);
2468c2ecf20Sopenharmony_ci	return ret < 0 ? ret : (ret != ARRAY_SIZE(msgs) ? -EIO : 0);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci/**
2508c2ecf20Sopenharmony_ci * goodix_i2c_write - write data to a register of the i2c slave device.
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * @client: i2c device.
2538c2ecf20Sopenharmony_ci * @reg: the register to write to.
2548c2ecf20Sopenharmony_ci * @buf: raw data buffer to write.
2558c2ecf20Sopenharmony_ci * @len: length of the buffer to write
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cistatic int goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf,
2588c2ecf20Sopenharmony_ci			    unsigned len)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	u8 *addr_buf;
2618c2ecf20Sopenharmony_ci	struct i2c_msg msg;
2628c2ecf20Sopenharmony_ci	int ret;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	addr_buf = kmalloc(len + 2, GFP_KERNEL);
2658c2ecf20Sopenharmony_ci	if (!addr_buf)
2668c2ecf20Sopenharmony_ci		return -ENOMEM;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	addr_buf[0] = reg >> 8;
2698c2ecf20Sopenharmony_ci	addr_buf[1] = reg & 0xFF;
2708c2ecf20Sopenharmony_ci	memcpy(&addr_buf[2], buf, len);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	msg.flags = 0;
2738c2ecf20Sopenharmony_ci	msg.addr = client->addr;
2748c2ecf20Sopenharmony_ci	msg.buf = addr_buf;
2758c2ecf20Sopenharmony_ci	msg.len = len + 2;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ret = i2c_transfer(client->adapter, &msg, 1);
2788c2ecf20Sopenharmony_ci	kfree(addr_buf);
2798c2ecf20Sopenharmony_ci	return ret < 0 ? ret : (ret != 1 ? -EIO : 0);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	return goodix_i2c_write(client, reg, &value, sizeof(value));
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic const struct goodix_chip_data *goodix_get_chip_data(const char *id)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	unsigned int i;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	for (i = 0; goodix_chip_ids[i].id; i++) {
2928c2ecf20Sopenharmony_ci		if (!strcmp(goodix_chip_ids[i].id, id))
2938c2ecf20Sopenharmony_ci			return goodix_chip_ids[i].data;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return &gt9x_chip_data;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	unsigned long max_timeout;
3028c2ecf20Sopenharmony_ci	int touch_num;
3038c2ecf20Sopenharmony_ci	int error;
3048c2ecf20Sopenharmony_ci	u16 addr = GOODIX_READ_COOR_ADDR;
3058c2ecf20Sopenharmony_ci	/*
3068c2ecf20Sopenharmony_ci	 * We are going to read 1-byte header,
3078c2ecf20Sopenharmony_ci	 * ts->contact_size * max(1, touch_num) bytes of coordinates
3088c2ecf20Sopenharmony_ci	 * and 1-byte footer which contains the touch-key code.
3098c2ecf20Sopenharmony_ci	 */
3108c2ecf20Sopenharmony_ci	const int header_contact_keycode_size = 1 + ts->contact_size + 1;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	/*
3138c2ecf20Sopenharmony_ci	 * The 'buffer status' bit, which indicates that the data is valid, is
3148c2ecf20Sopenharmony_ci	 * not set as soon as the interrupt is raised, but slightly after.
3158c2ecf20Sopenharmony_ci	 * This takes around 10 ms to happen, so we poll for 20 ms.
3168c2ecf20Sopenharmony_ci	 */
3178c2ecf20Sopenharmony_ci	max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
3188c2ecf20Sopenharmony_ci	do {
3198c2ecf20Sopenharmony_ci		error = goodix_i2c_read(ts->client, addr, data,
3208c2ecf20Sopenharmony_ci					header_contact_keycode_size);
3218c2ecf20Sopenharmony_ci		if (error) {
3228c2ecf20Sopenharmony_ci			dev_err(&ts->client->dev, "I2C transfer error: %d\n",
3238c2ecf20Sopenharmony_ci					error);
3248c2ecf20Sopenharmony_ci			return error;
3258c2ecf20Sopenharmony_ci		}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		if (data[0] & GOODIX_BUFFER_STATUS_READY) {
3288c2ecf20Sopenharmony_ci			touch_num = data[0] & 0x0f;
3298c2ecf20Sopenharmony_ci			if (touch_num > ts->max_touch_num)
3308c2ecf20Sopenharmony_ci				return -EPROTO;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci			if (touch_num > 1) {
3338c2ecf20Sopenharmony_ci				addr += header_contact_keycode_size;
3348c2ecf20Sopenharmony_ci				data += header_contact_keycode_size;
3358c2ecf20Sopenharmony_ci				error = goodix_i2c_read(ts->client,
3368c2ecf20Sopenharmony_ci						addr, data,
3378c2ecf20Sopenharmony_ci						ts->contact_size *
3388c2ecf20Sopenharmony_ci							(touch_num - 1));
3398c2ecf20Sopenharmony_ci				if (error)
3408c2ecf20Sopenharmony_ci					return error;
3418c2ecf20Sopenharmony_ci			}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci			return touch_num;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
3478c2ecf20Sopenharmony_ci	} while (time_before(jiffies, max_timeout));
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/*
3508c2ecf20Sopenharmony_ci	 * The Goodix panel will send spurious interrupts after a
3518c2ecf20Sopenharmony_ci	 * 'finger up' event, which will always cause a timeout.
3528c2ecf20Sopenharmony_ci	 */
3538c2ecf20Sopenharmony_ci	return -ENOMSG;
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	int id = coor_data[0] & 0x0F;
3598c2ecf20Sopenharmony_ci	int input_x = get_unaligned_le16(&coor_data[1]);
3608c2ecf20Sopenharmony_ci	int input_y = get_unaligned_le16(&coor_data[3]);
3618c2ecf20Sopenharmony_ci	int input_w = get_unaligned_le16(&coor_data[5]);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	input_mt_slot(ts->input_dev, id);
3648c2ecf20Sopenharmony_ci	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
3658c2ecf20Sopenharmony_ci	touchscreen_report_pos(ts->input_dev, &ts->prop,
3668c2ecf20Sopenharmony_ci			       input_x, input_y, true);
3678c2ecf20Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
3688c2ecf20Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	int id = coor_data[1] & 0x0F;
3748c2ecf20Sopenharmony_ci	int input_x = get_unaligned_le16(&coor_data[3]);
3758c2ecf20Sopenharmony_ci	int input_y = get_unaligned_le16(&coor_data[5]);
3768c2ecf20Sopenharmony_ci	int input_w = get_unaligned_le16(&coor_data[7]);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	input_mt_slot(ts->input_dev, id);
3798c2ecf20Sopenharmony_ci	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
3808c2ecf20Sopenharmony_ci	touchscreen_report_pos(ts->input_dev, &ts->prop,
3818c2ecf20Sopenharmony_ci			       input_x, input_y, true);
3828c2ecf20Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
3838c2ecf20Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	int touch_num;
3898c2ecf20Sopenharmony_ci	u8 key_value;
3908c2ecf20Sopenharmony_ci	int i;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (data[0] & GOODIX_HAVE_KEY) {
3938c2ecf20Sopenharmony_ci		touch_num = data[0] & 0x0f;
3948c2ecf20Sopenharmony_ci		key_value = data[1 + ts->contact_size * touch_num];
3958c2ecf20Sopenharmony_ci		for (i = 0; i < GOODIX_MAX_KEYS; i++)
3968c2ecf20Sopenharmony_ci			if (key_value & BIT(i))
3978c2ecf20Sopenharmony_ci				input_report_key(ts->input_dev,
3988c2ecf20Sopenharmony_ci						 ts->keymap[i], 1);
3998c2ecf20Sopenharmony_ci	} else {
4008c2ecf20Sopenharmony_ci		for (i = 0; i < GOODIX_MAX_KEYS; i++)
4018c2ecf20Sopenharmony_ci			input_report_key(ts->input_dev, ts->keymap[i], 0);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci/**
4068c2ecf20Sopenharmony_ci * goodix_process_events - Process incoming events
4078c2ecf20Sopenharmony_ci *
4088c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer
4098c2ecf20Sopenharmony_ci *
4108c2ecf20Sopenharmony_ci * Called when the IRQ is triggered. Read the current device state, and push
4118c2ecf20Sopenharmony_ci * the input events to the user space.
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_cistatic void goodix_process_events(struct goodix_ts_data *ts)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	u8  point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
4168c2ecf20Sopenharmony_ci	int touch_num;
4178c2ecf20Sopenharmony_ci	int i;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	touch_num = goodix_ts_read_input_report(ts, point_data);
4208c2ecf20Sopenharmony_ci	if (touch_num < 0)
4218c2ecf20Sopenharmony_ci		return;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	goodix_ts_report_key(ts, point_data);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	for (i = 0; i < touch_num; i++)
4268c2ecf20Sopenharmony_ci		if (ts->contact_size == 9)
4278c2ecf20Sopenharmony_ci			goodix_ts_report_touch_9b(ts,
4288c2ecf20Sopenharmony_ci				&point_data[1 + ts->contact_size * i]);
4298c2ecf20Sopenharmony_ci		else
4308c2ecf20Sopenharmony_ci			goodix_ts_report_touch_8b(ts,
4318c2ecf20Sopenharmony_ci				&point_data[1 + ts->contact_size * i]);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	input_mt_sync_frame(ts->input_dev);
4348c2ecf20Sopenharmony_ci	input_sync(ts->input_dev);
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/**
4388c2ecf20Sopenharmony_ci * goodix_ts_irq_handler - The IRQ handler
4398c2ecf20Sopenharmony_ci *
4408c2ecf20Sopenharmony_ci * @irq: interrupt number.
4418c2ecf20Sopenharmony_ci * @dev_id: private data pointer.
4428c2ecf20Sopenharmony_ci */
4438c2ecf20Sopenharmony_cistatic irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = dev_id;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	goodix_process_events(ts);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0) < 0)
4508c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "I2C write end_cmd error\n");
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic void goodix_free_irq(struct goodix_ts_data *ts)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	devm_free_irq(&ts->client->dev, ts->client->irq, ts);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int goodix_request_irq(struct goodix_ts_data *ts)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
4638c2ecf20Sopenharmony_ci					 NULL, goodix_ts_irq_handler,
4648c2ecf20Sopenharmony_ci					 ts->irq_flags, ts->client->name, ts);
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	int i, raw_cfg_len = len - 2;
4708c2ecf20Sopenharmony_ci	u8 check_sum = 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i++)
4738c2ecf20Sopenharmony_ci		check_sum += cfg[i];
4748c2ecf20Sopenharmony_ci	check_sum = (~check_sum) + 1;
4758c2ecf20Sopenharmony_ci	if (check_sum != cfg[raw_cfg_len]) {
4768c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
4778c2ecf20Sopenharmony_ci			"The checksum of the config fw is not correct");
4788c2ecf20Sopenharmony_ci		return -EINVAL;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (cfg[raw_cfg_len + 1] != 1) {
4828c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
4838c2ecf20Sopenharmony_ci			"Config fw must have Config_Fresh register set");
4848c2ecf20Sopenharmony_ci		return -EINVAL;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	return 0;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	int i, raw_cfg_len = ts->chip->config_len - 2;
4938c2ecf20Sopenharmony_ci	u8 check_sum = 0;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i++)
4968c2ecf20Sopenharmony_ci		check_sum += ts->config[i];
4978c2ecf20Sopenharmony_ci	check_sum = (~check_sum) + 1;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	ts->config[raw_cfg_len] = check_sum;
5008c2ecf20Sopenharmony_ci	ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, const u8 *cfg,
5048c2ecf20Sopenharmony_ci			       int len)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	int i, raw_cfg_len = len - 3;
5078c2ecf20Sopenharmony_ci	u16 check_sum = 0;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i += 2)
5108c2ecf20Sopenharmony_ci		check_sum += get_unaligned_be16(&cfg[i]);
5118c2ecf20Sopenharmony_ci	check_sum = (~check_sum) + 1;
5128c2ecf20Sopenharmony_ci	if (check_sum != get_unaligned_be16(&cfg[raw_cfg_len])) {
5138c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
5148c2ecf20Sopenharmony_ci			"The checksum of the config fw is not correct");
5158c2ecf20Sopenharmony_ci		return -EINVAL;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (cfg[raw_cfg_len + 2] != 1) {
5198c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
5208c2ecf20Sopenharmony_ci			"Config fw must have Config_Fresh register set");
5218c2ecf20Sopenharmony_ci		return -EINVAL;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	int i, raw_cfg_len = ts->chip->config_len - 3;
5308c2ecf20Sopenharmony_ci	u16 check_sum = 0;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i += 2)
5338c2ecf20Sopenharmony_ci		check_sum += get_unaligned_be16(&ts->config[i]);
5348c2ecf20Sopenharmony_ci	check_sum = (~check_sum) + 1;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]);
5378c2ecf20Sopenharmony_ci	ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/**
5418c2ecf20Sopenharmony_ci * goodix_check_cfg - Checks if config fw is valid
5428c2ecf20Sopenharmony_ci *
5438c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer
5448c2ecf20Sopenharmony_ci * @cfg: firmware config data
5458c2ecf20Sopenharmony_ci */
5468c2ecf20Sopenharmony_cistatic int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	if (len < GOODIX_CONFIG_MIN_LENGTH ||
5498c2ecf20Sopenharmony_ci	    len > GOODIX_CONFIG_MAX_LENGTH) {
5508c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
5518c2ecf20Sopenharmony_ci			"The length of the config fw is not correct");
5528c2ecf20Sopenharmony_ci		return -EINVAL;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return ts->chip->check_config(ts, cfg, len);
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci/**
5598c2ecf20Sopenharmony_ci * goodix_send_cfg - Write fw config to device
5608c2ecf20Sopenharmony_ci *
5618c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer
5628c2ecf20Sopenharmony_ci * @cfg: config firmware to write to device
5638c2ecf20Sopenharmony_ci */
5648c2ecf20Sopenharmony_cistatic int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	int error;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	error = goodix_check_cfg(ts, cfg, len);
5698c2ecf20Sopenharmony_ci	if (error)
5708c2ecf20Sopenharmony_ci		return error;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len);
5738c2ecf20Sopenharmony_ci	if (error) {
5748c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "Failed to write config data: %d",
5758c2ecf20Sopenharmony_ci			error);
5768c2ecf20Sopenharmony_ci		return error;
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci	dev_dbg(&ts->client->dev, "Config sent successfully.");
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/* Let the firmware reconfigure itself, so sleep for 10ms */
5818c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	return 0;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT
5878c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
5908c2ecf20Sopenharmony_ci	acpi_status status;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(handle, "INTI", NULL, NULL);
5938c2ecf20Sopenharmony_ci	return ACPI_SUCCESS(status) ? 0 : -EIO;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
5998c2ecf20Sopenharmony_ci	acpi_status status;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	status = acpi_execute_simple_method(handle, "INTO", value);
6028c2ecf20Sopenharmony_ci	return ACPI_SUCCESS(status) ? 0 : -EIO;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci#else
6058c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	dev_err(&ts->client->dev,
6088c2ecf20Sopenharmony_ci		"%s called on device without ACPI support\n", __func__);
6098c2ecf20Sopenharmony_ci	return -EINVAL;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	dev_err(&ts->client->dev,
6158c2ecf20Sopenharmony_ci		"%s called on device without ACPI support\n", __func__);
6168c2ecf20Sopenharmony_ci	return -EINVAL;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci#endif
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic int goodix_irq_direction_output(struct goodix_ts_data *ts, int value)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	switch (ts->irq_pin_access_method) {
6238c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_NONE:
6248c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
6258c2ecf20Sopenharmony_ci			"%s called without an irq_pin_access_method set\n",
6268c2ecf20Sopenharmony_ci			__func__);
6278c2ecf20Sopenharmony_ci		return -EINVAL;
6288c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_GPIO:
6298c2ecf20Sopenharmony_ci		return gpiod_direction_output(ts->gpiod_int, value);
6308c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
6318c2ecf20Sopenharmony_ci		/*
6328c2ecf20Sopenharmony_ci		 * The IRQ pin triggers on a falling edge, so its gets marked
6338c2ecf20Sopenharmony_ci		 * as active-low, use output_raw to avoid the value inversion.
6348c2ecf20Sopenharmony_ci		 */
6358c2ecf20Sopenharmony_ci		return gpiod_direction_output_raw(ts->gpiod_int, value);
6368c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
6378c2ecf20Sopenharmony_ci		return goodix_pin_acpi_output_method(ts, value);
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	return -EINVAL; /* Never reached */
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic int goodix_irq_direction_input(struct goodix_ts_data *ts)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	switch (ts->irq_pin_access_method) {
6468c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_NONE:
6478c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
6488c2ecf20Sopenharmony_ci			"%s called without an irq_pin_access_method set\n",
6498c2ecf20Sopenharmony_ci			__func__);
6508c2ecf20Sopenharmony_ci		return -EINVAL;
6518c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_GPIO:
6528c2ecf20Sopenharmony_ci		return gpiod_direction_input(ts->gpiod_int);
6538c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
6548c2ecf20Sopenharmony_ci		return gpiod_direction_input(ts->gpiod_int);
6558c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
6568c2ecf20Sopenharmony_ci		return goodix_pin_acpi_direction_input(ts);
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	return -EINVAL; /* Never reached */
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_cistatic int goodix_int_sync(struct goodix_ts_data *ts)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	int error;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	error = goodix_irq_direction_output(ts, 0);
6678c2ecf20Sopenharmony_ci	if (error)
6688c2ecf20Sopenharmony_ci		return error;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	msleep(50);				/* T5: 50ms */
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	error = goodix_irq_direction_input(ts);
6738c2ecf20Sopenharmony_ci	if (error)
6748c2ecf20Sopenharmony_ci		return error;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	return 0;
6778c2ecf20Sopenharmony_ci}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/**
6808c2ecf20Sopenharmony_ci * goodix_reset - Reset device during power on
6818c2ecf20Sopenharmony_ci *
6828c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer
6838c2ecf20Sopenharmony_ci */
6848c2ecf20Sopenharmony_cistatic int goodix_reset(struct goodix_ts_data *ts)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci	int error;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	/* begin select I2C slave addr */
6898c2ecf20Sopenharmony_ci	error = gpiod_direction_output(ts->gpiod_rst, 0);
6908c2ecf20Sopenharmony_ci	if (error)
6918c2ecf20Sopenharmony_ci		return error;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	msleep(20);				/* T2: > 10ms */
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
6968c2ecf20Sopenharmony_ci	error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
6978c2ecf20Sopenharmony_ci	if (error)
6988c2ecf20Sopenharmony_ci		return error;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	usleep_range(100, 2000);		/* T3: > 100us */
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	error = gpiod_direction_output(ts->gpiod_rst, 1);
7038c2ecf20Sopenharmony_ci	if (error)
7048c2ecf20Sopenharmony_ci		return error;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	usleep_range(6000, 10000);		/* T4: > 5ms */
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* end select I2C slave addr */
7098c2ecf20Sopenharmony_ci	error = gpiod_direction_input(ts->gpiod_rst);
7108c2ecf20Sopenharmony_ci	if (error)
7118c2ecf20Sopenharmony_ci		return error;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	error = goodix_int_sync(ts);
7148c2ecf20Sopenharmony_ci	if (error)
7158c2ecf20Sopenharmony_ci		return error;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return 0;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT
7218c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
7228c2ecf20Sopenharmony_ci#include <asm/intel-family.h>
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic const struct x86_cpu_id baytrail_cpu_ids[] = {
7258c2ecf20Sopenharmony_ci	{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, X86_FEATURE_ANY, },
7268c2ecf20Sopenharmony_ci	{}
7278c2ecf20Sopenharmony_ci};
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic inline bool is_byt(void)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	const struct x86_cpu_id *id = x86_match_cpu(baytrail_cpu_ids);
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	return !!id;
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false };
7378c2ecf20Sopenharmony_cistatic const struct acpi_gpio_params second_gpio = { 1, 0, false };
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_first_gpios[] = {
7408c2ecf20Sopenharmony_ci	{ GOODIX_GPIO_INT_NAME "-gpios", &first_gpio, 1 },
7418c2ecf20Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &second_gpio, 1 },
7428c2ecf20Sopenharmony_ci	{ },
7438c2ecf20Sopenharmony_ci};
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_last_gpios[] = {
7468c2ecf20Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
7478c2ecf20Sopenharmony_ci	{ GOODIX_GPIO_INT_NAME "-gpios", &second_gpio, 1 },
7488c2ecf20Sopenharmony_ci	{ },
7498c2ecf20Sopenharmony_ci};
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_reset_only_gpios[] = {
7528c2ecf20Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
7538c2ecf20Sopenharmony_ci	{ },
7548c2ecf20Sopenharmony_ci};
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic int goodix_resource(struct acpi_resource *ares, void *data)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = data;
7598c2ecf20Sopenharmony_ci	struct device *dev = &ts->client->dev;
7608c2ecf20Sopenharmony_ci	struct acpi_resource_gpio *gpio;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	switch (ares->type) {
7638c2ecf20Sopenharmony_ci	case ACPI_RESOURCE_TYPE_GPIO:
7648c2ecf20Sopenharmony_ci		gpio = &ares->data.gpio;
7658c2ecf20Sopenharmony_ci		if (gpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT) {
7668c2ecf20Sopenharmony_ci			if (ts->gpio_int_idx == -1) {
7678c2ecf20Sopenharmony_ci				ts->gpio_int_idx = ts->gpio_count;
7688c2ecf20Sopenharmony_ci			} else {
7698c2ecf20Sopenharmony_ci				dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n");
7708c2ecf20Sopenharmony_ci				ts->gpio_int_idx = -2;
7718c2ecf20Sopenharmony_ci			}
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci		ts->gpio_count++;
7748c2ecf20Sopenharmony_ci		break;
7758c2ecf20Sopenharmony_ci	default:
7768c2ecf20Sopenharmony_ci		break;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	return 0;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci/*
7838c2ecf20Sopenharmony_ci * This function gets called in case we fail to get the irq GPIO directly
7848c2ecf20Sopenharmony_ci * because the ACPI tables lack GPIO-name to APCI _CRS index mappings
7858c2ecf20Sopenharmony_ci * (no _DSD UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 data).
7868c2ecf20Sopenharmony_ci * In that case we add our own mapping and then goodix_get_gpio_config()
7878c2ecf20Sopenharmony_ci * retries to get the GPIOs based on the added mapping.
7888c2ecf20Sopenharmony_ci */
7898c2ecf20Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	const struct acpi_gpio_mapping *gpio_mapping = NULL;
7928c2ecf20Sopenharmony_ci	struct device *dev = &ts->client->dev;
7938c2ecf20Sopenharmony_ci	LIST_HEAD(resources);
7948c2ecf20Sopenharmony_ci	int ret;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	ts->gpio_count = 0;
7978c2ecf20Sopenharmony_ci	ts->gpio_int_idx = -1;
7988c2ecf20Sopenharmony_ci	ret = acpi_dev_get_resources(ACPI_COMPANION(dev), &resources,
7998c2ecf20Sopenharmony_ci				     goodix_resource, ts);
8008c2ecf20Sopenharmony_ci	if (ret < 0) {
8018c2ecf20Sopenharmony_ci		dev_err(dev, "Error getting ACPI resources: %d\n", ret);
8028c2ecf20Sopenharmony_ci		return ret;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	acpi_dev_free_resource_list(&resources);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
8088c2ecf20Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
8098c2ecf20Sopenharmony_ci		gpio_mapping = acpi_goodix_int_first_gpios;
8108c2ecf20Sopenharmony_ci	} else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) {
8118c2ecf20Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
8128c2ecf20Sopenharmony_ci		gpio_mapping = acpi_goodix_int_last_gpios;
8138c2ecf20Sopenharmony_ci	} else if (ts->gpio_count == 1 && ts->gpio_int_idx == -1 &&
8148c2ecf20Sopenharmony_ci		   acpi_has_method(ACPI_HANDLE(dev), "INTI") &&
8158c2ecf20Sopenharmony_ci		   acpi_has_method(ACPI_HANDLE(dev), "INTO")) {
8168c2ecf20Sopenharmony_ci		dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n");
8178c2ecf20Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD;
8188c2ecf20Sopenharmony_ci		gpio_mapping = acpi_goodix_reset_only_gpios;
8198c2ecf20Sopenharmony_ci	} else if (is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
8208c2ecf20Sopenharmony_ci		dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
8218c2ecf20Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
8228c2ecf20Sopenharmony_ci		gpio_mapping = acpi_goodix_int_last_gpios;
8238c2ecf20Sopenharmony_ci	} else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) {
8248c2ecf20Sopenharmony_ci		/*
8258c2ecf20Sopenharmony_ci		 * On newer devices there is only 1 GpioInt resource and _PS0
8268c2ecf20Sopenharmony_ci		 * does the whole reset sequence for us.
8278c2ecf20Sopenharmony_ci		 */
8288c2ecf20Sopenharmony_ci		acpi_device_fix_up_power(ACPI_COMPANION(dev));
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci		/*
8318c2ecf20Sopenharmony_ci		 * Before the _PS0 call the int GPIO may have been in output
8328c2ecf20Sopenharmony_ci		 * mode and the call should have put the int GPIO in input mode,
8338c2ecf20Sopenharmony_ci		 * but the GPIO subsys cached state may still think it is
8348c2ecf20Sopenharmony_ci		 * in output mode, causing gpiochip_lock_as_irq() failure.
8358c2ecf20Sopenharmony_ci		 *
8368c2ecf20Sopenharmony_ci		 * Add a mapping for the int GPIO to make the
8378c2ecf20Sopenharmony_ci		 * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed,
8388c2ecf20Sopenharmony_ci		 * which will explicitly set the direction to input.
8398c2ecf20Sopenharmony_ci		 */
8408c2ecf20Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
8418c2ecf20Sopenharmony_ci		gpio_mapping = acpi_goodix_int_first_gpios;
8428c2ecf20Sopenharmony_ci	} else {
8438c2ecf20Sopenharmony_ci		dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
8448c2ecf20Sopenharmony_ci			 ts->gpio_count, ts->gpio_int_idx);
8458c2ecf20Sopenharmony_ci		return -EINVAL;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
8498c2ecf20Sopenharmony_ci}
8508c2ecf20Sopenharmony_ci#else
8518c2ecf20Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	return -EINVAL;
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci#endif /* CONFIG_X86 && CONFIG_ACPI */
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci/**
8588c2ecf20Sopenharmony_ci * goodix_get_gpio_config - Get GPIO config from ACPI/DT
8598c2ecf20Sopenharmony_ci *
8608c2ecf20Sopenharmony_ci * @ts: goodix_ts_data pointer
8618c2ecf20Sopenharmony_ci */
8628c2ecf20Sopenharmony_cistatic int goodix_get_gpio_config(struct goodix_ts_data *ts)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	int error;
8658c2ecf20Sopenharmony_ci	struct device *dev;
8668c2ecf20Sopenharmony_ci	struct gpio_desc *gpiod;
8678c2ecf20Sopenharmony_ci	bool added_acpi_mappings = false;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	if (!ts->client)
8708c2ecf20Sopenharmony_ci		return -EINVAL;
8718c2ecf20Sopenharmony_ci	dev = &ts->client->dev;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	ts->avdd28 = devm_regulator_get(dev, "AVDD28");
8748c2ecf20Sopenharmony_ci	if (IS_ERR(ts->avdd28)) {
8758c2ecf20Sopenharmony_ci		error = PTR_ERR(ts->avdd28);
8768c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
8778c2ecf20Sopenharmony_ci			dev_err(dev,
8788c2ecf20Sopenharmony_ci				"Failed to get AVDD28 regulator: %d\n", error);
8798c2ecf20Sopenharmony_ci		return error;
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	ts->vddio = devm_regulator_get(dev, "VDDIO");
8838c2ecf20Sopenharmony_ci	if (IS_ERR(ts->vddio)) {
8848c2ecf20Sopenharmony_ci		error = PTR_ERR(ts->vddio);
8858c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
8868c2ecf20Sopenharmony_ci			dev_err(dev,
8878c2ecf20Sopenharmony_ci				"Failed to get VDDIO regulator: %d\n", error);
8888c2ecf20Sopenharmony_ci		return error;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ciretry_get_irq_gpio:
8928c2ecf20Sopenharmony_ci	/* Get the interrupt GPIO pin number */
8938c2ecf20Sopenharmony_ci	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
8948c2ecf20Sopenharmony_ci	if (IS_ERR(gpiod)) {
8958c2ecf20Sopenharmony_ci		error = PTR_ERR(gpiod);
8968c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
8978c2ecf20Sopenharmony_ci			dev_dbg(dev, "Failed to get %s GPIO: %d\n",
8988c2ecf20Sopenharmony_ci				GOODIX_GPIO_INT_NAME, error);
8998c2ecf20Sopenharmony_ci		return error;
9008c2ecf20Sopenharmony_ci	}
9018c2ecf20Sopenharmony_ci	if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) {
9028c2ecf20Sopenharmony_ci		added_acpi_mappings = true;
9038c2ecf20Sopenharmony_ci		if (goodix_add_acpi_gpio_mappings(ts) == 0)
9048c2ecf20Sopenharmony_ci			goto retry_get_irq_gpio;
9058c2ecf20Sopenharmony_ci	}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	ts->gpiod_int = gpiod;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Get the reset line GPIO pin number */
9108c2ecf20Sopenharmony_ci	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_IN);
9118c2ecf20Sopenharmony_ci	if (IS_ERR(gpiod)) {
9128c2ecf20Sopenharmony_ci		error = PTR_ERR(gpiod);
9138c2ecf20Sopenharmony_ci		if (error != -EPROBE_DEFER)
9148c2ecf20Sopenharmony_ci			dev_dbg(dev, "Failed to get %s GPIO: %d\n",
9158c2ecf20Sopenharmony_ci				GOODIX_GPIO_RST_NAME, error);
9168c2ecf20Sopenharmony_ci		return error;
9178c2ecf20Sopenharmony_ci	}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	ts->gpiod_rst = gpiod;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	switch (ts->irq_pin_access_method) {
9228c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
9238c2ecf20Sopenharmony_ci		/*
9248c2ecf20Sopenharmony_ci		 * We end up here if goodix_add_acpi_gpio_mappings() has
9258c2ecf20Sopenharmony_ci		 * called devm_acpi_dev_add_driver_gpios() because the ACPI
9268c2ecf20Sopenharmony_ci		 * tables did not contain name to index mappings.
9278c2ecf20Sopenharmony_ci		 * Check that we successfully got both GPIOs after we've
9288c2ecf20Sopenharmony_ci		 * added our own acpi_gpio_mapping and if we did not get both
9298c2ecf20Sopenharmony_ci		 * GPIOs reset irq_pin_access_method to IRQ_PIN_ACCESS_NONE.
9308c2ecf20Sopenharmony_ci		 */
9318c2ecf20Sopenharmony_ci		if (!ts->gpiod_int || !ts->gpiod_rst)
9328c2ecf20Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
9338c2ecf20Sopenharmony_ci		break;
9348c2ecf20Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
9358c2ecf20Sopenharmony_ci		if (!ts->gpiod_rst)
9368c2ecf20Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci	default:
9398c2ecf20Sopenharmony_ci		if (ts->gpiod_int && ts->gpiod_rst) {
9408c2ecf20Sopenharmony_ci			ts->reset_controller_at_probe = true;
9418c2ecf20Sopenharmony_ci			ts->load_cfg_from_disk = true;
9428c2ecf20Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_GPIO;
9438c2ecf20Sopenharmony_ci		}
9448c2ecf20Sopenharmony_ci	}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci/**
9508c2ecf20Sopenharmony_ci * goodix_read_config - Read the embedded configuration of the panel
9518c2ecf20Sopenharmony_ci *
9528c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer
9538c2ecf20Sopenharmony_ci *
9548c2ecf20Sopenharmony_ci * Must be called during probe
9558c2ecf20Sopenharmony_ci */
9568c2ecf20Sopenharmony_cistatic void goodix_read_config(struct goodix_ts_data *ts)
9578c2ecf20Sopenharmony_ci{
9588c2ecf20Sopenharmony_ci	int x_max, y_max;
9598c2ecf20Sopenharmony_ci	int error;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	error = goodix_i2c_read(ts->client, ts->chip->config_addr,
9628c2ecf20Sopenharmony_ci				ts->config, ts->chip->config_len);
9638c2ecf20Sopenharmony_ci	if (error) {
9648c2ecf20Sopenharmony_ci		dev_warn(&ts->client->dev, "Error reading config: %d\n",
9658c2ecf20Sopenharmony_ci			 error);
9668c2ecf20Sopenharmony_ci		ts->int_trigger_type = GOODIX_INT_TRIGGER;
9678c2ecf20Sopenharmony_ci		ts->max_touch_num = GOODIX_MAX_CONTACTS;
9688c2ecf20Sopenharmony_ci		return;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
9728c2ecf20Sopenharmony_ci	ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]);
9758c2ecf20Sopenharmony_ci	y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]);
9768c2ecf20Sopenharmony_ci	if (x_max && y_max) {
9778c2ecf20Sopenharmony_ci		input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1);
9788c2ecf20Sopenharmony_ci		input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1);
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	ts->chip->calc_config_checksum(ts);
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci/**
9858c2ecf20Sopenharmony_ci * goodix_read_version - Read goodix touchscreen version
9868c2ecf20Sopenharmony_ci *
9878c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer
9888c2ecf20Sopenharmony_ci */
9898c2ecf20Sopenharmony_cistatic int goodix_read_version(struct goodix_ts_data *ts)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	int error;
9928c2ecf20Sopenharmony_ci	u8 buf[6];
9938c2ecf20Sopenharmony_ci	char id_str[GOODIX_ID_MAX_LEN + 1];
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
9968c2ecf20Sopenharmony_ci	if (error) {
9978c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "read version failed: %d\n", error);
9988c2ecf20Sopenharmony_ci		return error;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	memcpy(id_str, buf, GOODIX_ID_MAX_LEN);
10028c2ecf20Sopenharmony_ci	id_str[GOODIX_ID_MAX_LEN] = 0;
10038c2ecf20Sopenharmony_ci	strscpy(ts->id, id_str, GOODIX_ID_MAX_LEN + 1);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	ts->version = get_unaligned_le16(&buf[4]);
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id,
10088c2ecf20Sopenharmony_ci		 ts->version);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	return 0;
10118c2ecf20Sopenharmony_ci}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci/**
10148c2ecf20Sopenharmony_ci * goodix_i2c_test - I2C test function to check if the device answers.
10158c2ecf20Sopenharmony_ci *
10168c2ecf20Sopenharmony_ci * @client: the i2c client
10178c2ecf20Sopenharmony_ci */
10188c2ecf20Sopenharmony_cistatic int goodix_i2c_test(struct i2c_client *client)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	int retry = 0;
10218c2ecf20Sopenharmony_ci	int error;
10228c2ecf20Sopenharmony_ci	u8 test;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	while (retry++ < 2) {
10258c2ecf20Sopenharmony_ci		error = goodix_i2c_read(client, GOODIX_REG_ID,
10268c2ecf20Sopenharmony_ci					&test, 1);
10278c2ecf20Sopenharmony_ci		if (!error)
10288c2ecf20Sopenharmony_ci			return 0;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci		dev_err(&client->dev, "i2c test failed attempt %d: %d\n",
10318c2ecf20Sopenharmony_ci			retry, error);
10328c2ecf20Sopenharmony_ci		msleep(20);
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return error;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci/**
10398c2ecf20Sopenharmony_ci * goodix_configure_dev - Finish device initialization
10408c2ecf20Sopenharmony_ci *
10418c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer
10428c2ecf20Sopenharmony_ci *
10438c2ecf20Sopenharmony_ci * Must be called from probe to finish initialization of the device.
10448c2ecf20Sopenharmony_ci * Contains the common initialization code for both devices that
10458c2ecf20Sopenharmony_ci * declare gpio pins and devices that do not. It is either called
10468c2ecf20Sopenharmony_ci * directly from probe or from request_firmware_wait callback.
10478c2ecf20Sopenharmony_ci */
10488c2ecf20Sopenharmony_cistatic int goodix_configure_dev(struct goodix_ts_data *ts)
10498c2ecf20Sopenharmony_ci{
10508c2ecf20Sopenharmony_ci	int error;
10518c2ecf20Sopenharmony_ci	int i;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	ts->int_trigger_type = GOODIX_INT_TRIGGER;
10548c2ecf20Sopenharmony_ci	ts->max_touch_num = GOODIX_MAX_CONTACTS;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	ts->input_dev = devm_input_allocate_device(&ts->client->dev);
10578c2ecf20Sopenharmony_ci	if (!ts->input_dev) {
10588c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "Failed to allocate input device.");
10598c2ecf20Sopenharmony_ci		return -ENOMEM;
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	ts->input_dev->name = "Goodix Capacitive TouchScreen";
10638c2ecf20Sopenharmony_ci	ts->input_dev->phys = "input/ts";
10648c2ecf20Sopenharmony_ci	ts->input_dev->id.bustype = BUS_I2C;
10658c2ecf20Sopenharmony_ci	ts->input_dev->id.vendor = 0x0416;
10668c2ecf20Sopenharmony_ci	if (kstrtou16(ts->id, 10, &ts->input_dev->id.product))
10678c2ecf20Sopenharmony_ci		ts->input_dev->id.product = 0x1001;
10688c2ecf20Sopenharmony_ci	ts->input_dev->id.version = ts->version;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	ts->input_dev->keycode = ts->keymap;
10718c2ecf20Sopenharmony_ci	ts->input_dev->keycodesize = sizeof(ts->keymap[0]);
10728c2ecf20Sopenharmony_ci	ts->input_dev->keycodemax = GOODIX_MAX_KEYS;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	/* Capacitive Windows/Home button on some devices */
10758c2ecf20Sopenharmony_ci	for (i = 0; i < GOODIX_MAX_KEYS; ++i) {
10768c2ecf20Sopenharmony_ci		if (i == 0)
10778c2ecf20Sopenharmony_ci			ts->keymap[i] = KEY_LEFTMETA;
10788c2ecf20Sopenharmony_ci		else
10798c2ecf20Sopenharmony_ci			ts->keymap[i] = KEY_F1 + (i - 1);
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci		input_set_capability(ts->input_dev, EV_KEY, ts->keymap[i]);
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
10858c2ecf20Sopenharmony_ci	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
10868c2ecf20Sopenharmony_ci	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
10878c2ecf20Sopenharmony_ci	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ciretry_read_config:
10908c2ecf20Sopenharmony_ci	/* Read configuration and apply touchscreen parameters */
10918c2ecf20Sopenharmony_ci	goodix_read_config(ts);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	/* Try overriding touchscreen parameters via device properties */
10948c2ecf20Sopenharmony_ci	touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
10978c2ecf20Sopenharmony_ci		if (!ts->reset_controller_at_probe &&
10988c2ecf20Sopenharmony_ci		    ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
10998c2ecf20Sopenharmony_ci			dev_info(&ts->client->dev, "Config not set, resetting controller\n");
11008c2ecf20Sopenharmony_ci			/* Retry after a controller reset */
11018c2ecf20Sopenharmony_ci			ts->reset_controller_at_probe = true;
11028c2ecf20Sopenharmony_ci			error = goodix_reset(ts);
11038c2ecf20Sopenharmony_ci			if (error)
11048c2ecf20Sopenharmony_ci				return error;
11058c2ecf20Sopenharmony_ci			goto retry_read_config;
11068c2ecf20Sopenharmony_ci		}
11078c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
11088c2ecf20Sopenharmony_ci			"Invalid config (%d, %d, %d), using defaults\n",
11098c2ecf20Sopenharmony_ci			ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
11108c2ecf20Sopenharmony_ci		ts->prop.max_x = GOODIX_MAX_WIDTH - 1;
11118c2ecf20Sopenharmony_ci		ts->prop.max_y = GOODIX_MAX_HEIGHT - 1;
11128c2ecf20Sopenharmony_ci		ts->max_touch_num = GOODIX_MAX_CONTACTS;
11138c2ecf20Sopenharmony_ci		input_abs_set_max(ts->input_dev,
11148c2ecf20Sopenharmony_ci				  ABS_MT_POSITION_X, ts->prop.max_x);
11158c2ecf20Sopenharmony_ci		input_abs_set_max(ts->input_dev,
11168c2ecf20Sopenharmony_ci				  ABS_MT_POSITION_Y, ts->prop.max_y);
11178c2ecf20Sopenharmony_ci	}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (dmi_check_system(nine_bytes_report)) {
11208c2ecf20Sopenharmony_ci		ts->contact_size = 9;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci		dev_dbg(&ts->client->dev,
11238c2ecf20Sopenharmony_ci			"Non-standard 9-bytes report format quirk\n");
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	if (dmi_check_system(inverted_x_screen)) {
11278c2ecf20Sopenharmony_ci		ts->prop.invert_x = true;
11288c2ecf20Sopenharmony_ci		dev_dbg(&ts->client->dev,
11298c2ecf20Sopenharmony_ci			"Applying 'inverted x screen' quirk\n");
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
11338c2ecf20Sopenharmony_ci				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
11348c2ecf20Sopenharmony_ci	if (error) {
11358c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
11368c2ecf20Sopenharmony_ci			"Failed to initialize MT slots: %d", error);
11378c2ecf20Sopenharmony_ci		return error;
11388c2ecf20Sopenharmony_ci	}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	error = input_register_device(ts->input_dev);
11418c2ecf20Sopenharmony_ci	if (error) {
11428c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev,
11438c2ecf20Sopenharmony_ci			"Failed to register input device: %d", error);
11448c2ecf20Sopenharmony_ci		return error;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
11488c2ecf20Sopenharmony_ci	error = goodix_request_irq(ts);
11498c2ecf20Sopenharmony_ci	if (error) {
11508c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "request IRQ failed: %d\n", error);
11518c2ecf20Sopenharmony_ci		return error;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	return 0;
11558c2ecf20Sopenharmony_ci}
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci/**
11588c2ecf20Sopenharmony_ci * goodix_config_cb - Callback to finish device init
11598c2ecf20Sopenharmony_ci *
11608c2ecf20Sopenharmony_ci * @ts: our goodix_ts_data pointer
11618c2ecf20Sopenharmony_ci *
11628c2ecf20Sopenharmony_ci * request_firmware_wait callback that finishes
11638c2ecf20Sopenharmony_ci * initialization of the device.
11648c2ecf20Sopenharmony_ci */
11658c2ecf20Sopenharmony_cistatic void goodix_config_cb(const struct firmware *cfg, void *ctx)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = ctx;
11688c2ecf20Sopenharmony_ci	int error;
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	if (cfg) {
11718c2ecf20Sopenharmony_ci		/* send device configuration to the firmware */
11728c2ecf20Sopenharmony_ci		error = goodix_send_cfg(ts, cfg->data, cfg->size);
11738c2ecf20Sopenharmony_ci		if (error)
11748c2ecf20Sopenharmony_ci			goto err_release_cfg;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	goodix_configure_dev(ts);
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cierr_release_cfg:
11808c2ecf20Sopenharmony_ci	release_firmware(cfg);
11818c2ecf20Sopenharmony_ci	complete_all(&ts->firmware_loading_complete);
11828c2ecf20Sopenharmony_ci}
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_cistatic void goodix_disable_regulators(void *arg)
11858c2ecf20Sopenharmony_ci{
11868c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = arg;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	regulator_disable(ts->vddio);
11898c2ecf20Sopenharmony_ci	regulator_disable(ts->avdd28);
11908c2ecf20Sopenharmony_ci}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic int goodix_ts_probe(struct i2c_client *client,
11938c2ecf20Sopenharmony_ci			   const struct i2c_device_id *id)
11948c2ecf20Sopenharmony_ci{
11958c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts;
11968c2ecf20Sopenharmony_ci	int error;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
12018c2ecf20Sopenharmony_ci		dev_err(&client->dev, "I2C check functionality failed.\n");
12028c2ecf20Sopenharmony_ci		return -ENXIO;
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
12068c2ecf20Sopenharmony_ci	if (!ts)
12078c2ecf20Sopenharmony_ci		return -ENOMEM;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	ts->client = client;
12108c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, ts);
12118c2ecf20Sopenharmony_ci	init_completion(&ts->firmware_loading_complete);
12128c2ecf20Sopenharmony_ci	ts->contact_size = GOODIX_CONTACT_SIZE;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	error = goodix_get_gpio_config(ts);
12158c2ecf20Sopenharmony_ci	if (error)
12168c2ecf20Sopenharmony_ci		return error;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	/* power up the controller */
12198c2ecf20Sopenharmony_ci	error = regulator_enable(ts->avdd28);
12208c2ecf20Sopenharmony_ci	if (error) {
12218c2ecf20Sopenharmony_ci		dev_err(&client->dev,
12228c2ecf20Sopenharmony_ci			"Failed to enable AVDD28 regulator: %d\n",
12238c2ecf20Sopenharmony_ci			error);
12248c2ecf20Sopenharmony_ci		return error;
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	error = regulator_enable(ts->vddio);
12288c2ecf20Sopenharmony_ci	if (error) {
12298c2ecf20Sopenharmony_ci		dev_err(&client->dev,
12308c2ecf20Sopenharmony_ci			"Failed to enable VDDIO regulator: %d\n",
12318c2ecf20Sopenharmony_ci			error);
12328c2ecf20Sopenharmony_ci		regulator_disable(ts->avdd28);
12338c2ecf20Sopenharmony_ci		return error;
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	error = devm_add_action_or_reset(&client->dev,
12378c2ecf20Sopenharmony_ci					 goodix_disable_regulators, ts);
12388c2ecf20Sopenharmony_ci	if (error)
12398c2ecf20Sopenharmony_ci		return error;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_cireset:
12428c2ecf20Sopenharmony_ci	if (ts->reset_controller_at_probe) {
12438c2ecf20Sopenharmony_ci		/* reset the controller */
12448c2ecf20Sopenharmony_ci		error = goodix_reset(ts);
12458c2ecf20Sopenharmony_ci		if (error) {
12468c2ecf20Sopenharmony_ci			dev_err(&client->dev, "Controller reset failed.\n");
12478c2ecf20Sopenharmony_ci			return error;
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci	}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	error = goodix_i2c_test(client);
12528c2ecf20Sopenharmony_ci	if (error) {
12538c2ecf20Sopenharmony_ci		if (!ts->reset_controller_at_probe &&
12548c2ecf20Sopenharmony_ci		    ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
12558c2ecf20Sopenharmony_ci			/* Retry after a controller reset */
12568c2ecf20Sopenharmony_ci			ts->reset_controller_at_probe = true;
12578c2ecf20Sopenharmony_ci			goto reset;
12588c2ecf20Sopenharmony_ci		}
12598c2ecf20Sopenharmony_ci		dev_err(&client->dev, "I2C communication failure: %d\n", error);
12608c2ecf20Sopenharmony_ci		return error;
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	error = goodix_read_version(ts);
12648c2ecf20Sopenharmony_ci	if (error) {
12658c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Read version failed.\n");
12668c2ecf20Sopenharmony_ci		return error;
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	ts->chip = goodix_get_chip_data(ts->id);
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci	if (ts->load_cfg_from_disk) {
12728c2ecf20Sopenharmony_ci		/* update device config */
12738c2ecf20Sopenharmony_ci		ts->cfg_name = devm_kasprintf(&client->dev, GFP_KERNEL,
12748c2ecf20Sopenharmony_ci					      "goodix_%s_cfg.bin", ts->id);
12758c2ecf20Sopenharmony_ci		if (!ts->cfg_name)
12768c2ecf20Sopenharmony_ci			return -ENOMEM;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci		error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
12798c2ecf20Sopenharmony_ci						&client->dev, GFP_KERNEL, ts,
12808c2ecf20Sopenharmony_ci						goodix_config_cb);
12818c2ecf20Sopenharmony_ci		if (error) {
12828c2ecf20Sopenharmony_ci			dev_err(&client->dev,
12838c2ecf20Sopenharmony_ci				"Failed to invoke firmware loader: %d\n",
12848c2ecf20Sopenharmony_ci				error);
12858c2ecf20Sopenharmony_ci			return error;
12868c2ecf20Sopenharmony_ci		}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		return 0;
12898c2ecf20Sopenharmony_ci	} else {
12908c2ecf20Sopenharmony_ci		error = goodix_configure_dev(ts);
12918c2ecf20Sopenharmony_ci		if (error)
12928c2ecf20Sopenharmony_ci			return error;
12938c2ecf20Sopenharmony_ci	}
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	return 0;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic int goodix_ts_remove(struct i2c_client *client)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (ts->load_cfg_from_disk)
13038c2ecf20Sopenharmony_ci		wait_for_completion(&ts->firmware_loading_complete);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	return 0;
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_cistatic int __maybe_unused goodix_suspend(struct device *dev)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13118c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
13128c2ecf20Sopenharmony_ci	int error;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (ts->load_cfg_from_disk)
13158c2ecf20Sopenharmony_ci		wait_for_completion(&ts->firmware_loading_complete);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	/* We need gpio pins to suspend/resume */
13188c2ecf20Sopenharmony_ci	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
13198c2ecf20Sopenharmony_ci		disable_irq(client->irq);
13208c2ecf20Sopenharmony_ci		return 0;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	/* Free IRQ as IRQ pin is used as output in the suspend sequence */
13248c2ecf20Sopenharmony_ci	goodix_free_irq(ts);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	/* Output LOW on the INT pin for 5 ms */
13278c2ecf20Sopenharmony_ci	error = goodix_irq_direction_output(ts, 0);
13288c2ecf20Sopenharmony_ci	if (error) {
13298c2ecf20Sopenharmony_ci		goodix_request_irq(ts);
13308c2ecf20Sopenharmony_ci		return error;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	usleep_range(5000, 6000);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
13368c2ecf20Sopenharmony_ci				    GOODIX_CMD_SCREEN_OFF);
13378c2ecf20Sopenharmony_ci	if (error) {
13388c2ecf20Sopenharmony_ci		dev_err(&ts->client->dev, "Screen off command failed\n");
13398c2ecf20Sopenharmony_ci		goodix_irq_direction_input(ts);
13408c2ecf20Sopenharmony_ci		goodix_request_irq(ts);
13418c2ecf20Sopenharmony_ci		return -EAGAIN;
13428c2ecf20Sopenharmony_ci	}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	/*
13458c2ecf20Sopenharmony_ci	 * The datasheet specifies that the interval between sending screen-off
13468c2ecf20Sopenharmony_ci	 * command and wake-up should be longer than 58 ms. To avoid waking up
13478c2ecf20Sopenharmony_ci	 * sooner, delay 58ms here.
13488c2ecf20Sopenharmony_ci	 */
13498c2ecf20Sopenharmony_ci	msleep(58);
13508c2ecf20Sopenharmony_ci	return 0;
13518c2ecf20Sopenharmony_ci}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_cistatic int __maybe_unused goodix_resume(struct device *dev)
13548c2ecf20Sopenharmony_ci{
13558c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
13568c2ecf20Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
13578c2ecf20Sopenharmony_ci	u8 config_ver;
13588c2ecf20Sopenharmony_ci	int error;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
13618c2ecf20Sopenharmony_ci		enable_irq(client->irq);
13628c2ecf20Sopenharmony_ci		return 0;
13638c2ecf20Sopenharmony_ci	}
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	/*
13668c2ecf20Sopenharmony_ci	 * Exit sleep mode by outputting HIGH level to INT pin
13678c2ecf20Sopenharmony_ci	 * for 2ms~5ms.
13688c2ecf20Sopenharmony_ci	 */
13698c2ecf20Sopenharmony_ci	error = goodix_irq_direction_output(ts, 1);
13708c2ecf20Sopenharmony_ci	if (error)
13718c2ecf20Sopenharmony_ci		return error;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	usleep_range(2000, 5000);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	error = goodix_int_sync(ts);
13768c2ecf20Sopenharmony_ci	if (error)
13778c2ecf20Sopenharmony_ci		return error;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	error = goodix_i2c_read(ts->client, ts->chip->config_addr,
13808c2ecf20Sopenharmony_ci				&config_ver, 1);
13818c2ecf20Sopenharmony_ci	if (error)
13828c2ecf20Sopenharmony_ci		dev_warn(dev, "Error reading config version: %d, resetting controller\n",
13838c2ecf20Sopenharmony_ci			 error);
13848c2ecf20Sopenharmony_ci	else if (config_ver != ts->config[0])
13858c2ecf20Sopenharmony_ci		dev_info(dev, "Config version mismatch %d != %d, resetting controller\n",
13868c2ecf20Sopenharmony_ci			 config_ver, ts->config[0]);
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (error != 0 || config_ver != ts->config[0]) {
13898c2ecf20Sopenharmony_ci		error = goodix_reset(ts);
13908c2ecf20Sopenharmony_ci		if (error) {
13918c2ecf20Sopenharmony_ci			dev_err(dev, "Controller reset failed.\n");
13928c2ecf20Sopenharmony_ci			return error;
13938c2ecf20Sopenharmony_ci		}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci		error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
13968c2ecf20Sopenharmony_ci		if (error)
13978c2ecf20Sopenharmony_ci			return error;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	error = goodix_request_irq(ts);
14018c2ecf20Sopenharmony_ci	if (error)
14028c2ecf20Sopenharmony_ci		return error;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	return 0;
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_cistatic const struct i2c_device_id goodix_ts_id[] = {
14108c2ecf20Sopenharmony_ci	{ "GDIX1001:00", 0 },
14118c2ecf20Sopenharmony_ci	{ }
14128c2ecf20Sopenharmony_ci};
14138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, goodix_ts_id);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
14168c2ecf20Sopenharmony_cistatic const struct acpi_device_id goodix_acpi_match[] = {
14178c2ecf20Sopenharmony_ci	{ "GDIX1001", 0 },
14188c2ecf20Sopenharmony_ci	{ "GDIX1002", 0 },
14198c2ecf20Sopenharmony_ci	{ }
14208c2ecf20Sopenharmony_ci};
14218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
14228c2ecf20Sopenharmony_ci#endif
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
14258c2ecf20Sopenharmony_cistatic const struct of_device_id goodix_of_match[] = {
14268c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt1151" },
14278c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt1158" },
14288c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt5663" },
14298c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt5688" },
14308c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt911" },
14318c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt9110" },
14328c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt912" },
14338c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt9147" },
14348c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt917s" },
14358c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt927" },
14368c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt9271" },
14378c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt928" },
14388c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt9286" },
14398c2ecf20Sopenharmony_ci	{ .compatible = "goodix,gt967" },
14408c2ecf20Sopenharmony_ci	{ }
14418c2ecf20Sopenharmony_ci};
14428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, goodix_of_match);
14438c2ecf20Sopenharmony_ci#endif
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_cistatic struct i2c_driver goodix_ts_driver = {
14468c2ecf20Sopenharmony_ci	.probe = goodix_ts_probe,
14478c2ecf20Sopenharmony_ci	.remove = goodix_ts_remove,
14488c2ecf20Sopenharmony_ci	.id_table = goodix_ts_id,
14498c2ecf20Sopenharmony_ci	.driver = {
14508c2ecf20Sopenharmony_ci		.name = "Goodix-TS",
14518c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(goodix_acpi_match),
14528c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(goodix_of_match),
14538c2ecf20Sopenharmony_ci		.pm = &goodix_pm_ops,
14548c2ecf20Sopenharmony_ci	},
14558c2ecf20Sopenharmony_ci};
14568c2ecf20Sopenharmony_cimodule_i2c_driver(goodix_ts_driver);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
14598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
14608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Goodix touchscreen driver");
14618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1462