162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for Goodix Touchscreens
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2014 Red Hat Inc.
662306a36Sopenharmony_ci *  Copyright (c) 2015 K. Merker <merker@debian.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  This code is based on gt9xx.c authored by andrew@goodix.com:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  2010 - 2012 Goodix Technology.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/dmi.h>
1662306a36Sopenharmony_ci#include <linux/firmware.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/irq.h>
2062306a36Sopenharmony_ci#include <linux/interrupt.h>
2162306a36Sopenharmony_ci#include <linux/platform_data/x86/soc.h>
2262306a36Sopenharmony_ci#include <linux/slab.h>
2362306a36Sopenharmony_ci#include <linux/acpi.h>
2462306a36Sopenharmony_ci#include <linux/of.h>
2562306a36Sopenharmony_ci#include <asm/unaligned.h>
2662306a36Sopenharmony_ci#include "goodix.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define GOODIX_GPIO_INT_NAME		"irq"
2962306a36Sopenharmony_ci#define GOODIX_GPIO_RST_NAME		"reset"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define GOODIX_MAX_HEIGHT		4096
3262306a36Sopenharmony_ci#define GOODIX_MAX_WIDTH		4096
3362306a36Sopenharmony_ci#define GOODIX_INT_TRIGGER		1
3462306a36Sopenharmony_ci#define GOODIX_CONTACT_SIZE		8
3562306a36Sopenharmony_ci#define GOODIX_MAX_CONTACT_SIZE		9
3662306a36Sopenharmony_ci#define GOODIX_MAX_CONTACTS		10
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define GOODIX_CONFIG_MIN_LENGTH	186
3962306a36Sopenharmony_ci#define GOODIX_CONFIG_911_LENGTH	186
4062306a36Sopenharmony_ci#define GOODIX_CONFIG_967_LENGTH	228
4162306a36Sopenharmony_ci#define GOODIX_CONFIG_GT9X_LENGTH	240
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define GOODIX_BUFFER_STATUS_READY	BIT(7)
4462306a36Sopenharmony_ci#define GOODIX_HAVE_KEY			BIT(4)
4562306a36Sopenharmony_ci#define GOODIX_BUFFER_STATUS_TIMEOUT	20
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define RESOLUTION_LOC		1
4862306a36Sopenharmony_ci#define MAX_CONTACTS_LOC	5
4962306a36Sopenharmony_ci#define TRIGGER_LOC		6
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* Our special handling for GPIO accesses through ACPI is x86 specific */
5262306a36Sopenharmony_ci#if defined CONFIG_X86 && defined CONFIG_ACPI
5362306a36Sopenharmony_ci#define ACPI_GPIO_SUPPORT
5462306a36Sopenharmony_ci#endif
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct goodix_chip_id {
5762306a36Sopenharmony_ci	const char *id;
5862306a36Sopenharmony_ci	const struct goodix_chip_data *data;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts,
6262306a36Sopenharmony_ci			      const u8 *cfg, int len);
6362306a36Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts,
6462306a36Sopenharmony_ci			       const u8 *cfg, int len);
6562306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts);
6662306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const struct goodix_chip_data gt1x_chip_data = {
6962306a36Sopenharmony_ci	.config_addr		= GOODIX_GT1X_REG_CONFIG_DATA,
7062306a36Sopenharmony_ci	.config_len		= GOODIX_CONFIG_GT9X_LENGTH,
7162306a36Sopenharmony_ci	.check_config		= goodix_check_cfg_16,
7262306a36Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_16,
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic const struct goodix_chip_data gt911_chip_data = {
7662306a36Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
7762306a36Sopenharmony_ci	.config_len		= GOODIX_CONFIG_911_LENGTH,
7862306a36Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
7962306a36Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic const struct goodix_chip_data gt967_chip_data = {
8362306a36Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
8462306a36Sopenharmony_ci	.config_len		= GOODIX_CONFIG_967_LENGTH,
8562306a36Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
8662306a36Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic const struct goodix_chip_data gt9x_chip_data = {
9062306a36Sopenharmony_ci	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
9162306a36Sopenharmony_ci	.config_len		= GOODIX_CONFIG_GT9X_LENGTH,
9262306a36Sopenharmony_ci	.check_config		= goodix_check_cfg_8,
9362306a36Sopenharmony_ci	.calc_config_checksum	= goodix_calc_cfg_checksum_8,
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic const struct goodix_chip_id goodix_chip_ids[] = {
9762306a36Sopenharmony_ci	{ .id = "1151", .data = &gt1x_chip_data },
9862306a36Sopenharmony_ci	{ .id = "1158", .data = &gt1x_chip_data },
9962306a36Sopenharmony_ci	{ .id = "5663", .data = &gt1x_chip_data },
10062306a36Sopenharmony_ci	{ .id = "5688", .data = &gt1x_chip_data },
10162306a36Sopenharmony_ci	{ .id = "917S", .data = &gt1x_chip_data },
10262306a36Sopenharmony_ci	{ .id = "9286", .data = &gt1x_chip_data },
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	{ .id = "911", .data = &gt911_chip_data },
10562306a36Sopenharmony_ci	{ .id = "9271", .data = &gt911_chip_data },
10662306a36Sopenharmony_ci	{ .id = "9110", .data = &gt911_chip_data },
10762306a36Sopenharmony_ci	{ .id = "9111", .data = &gt911_chip_data },
10862306a36Sopenharmony_ci	{ .id = "927", .data = &gt911_chip_data },
10962306a36Sopenharmony_ci	{ .id = "928", .data = &gt911_chip_data },
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	{ .id = "912", .data = &gt967_chip_data },
11262306a36Sopenharmony_ci	{ .id = "9147", .data = &gt967_chip_data },
11362306a36Sopenharmony_ci	{ .id = "967", .data = &gt967_chip_data },
11462306a36Sopenharmony_ci	{ }
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic const unsigned long goodix_irq_flags[] = {
11862306a36Sopenharmony_ci	IRQ_TYPE_EDGE_RISING,
11962306a36Sopenharmony_ci	IRQ_TYPE_EDGE_FALLING,
12062306a36Sopenharmony_ci	IRQ_TYPE_LEVEL_LOW,
12162306a36Sopenharmony_ci	IRQ_TYPE_LEVEL_HIGH,
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic const struct dmi_system_id nine_bytes_report[] = {
12562306a36Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86)
12662306a36Sopenharmony_ci	{
12762306a36Sopenharmony_ci		/* Lenovo Yoga Book X90F / X90L */
12862306a36Sopenharmony_ci		.matches = {
12962306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
13062306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
13162306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
13262306a36Sopenharmony_ci		}
13362306a36Sopenharmony_ci	},
13462306a36Sopenharmony_ci	{
13562306a36Sopenharmony_ci		/* Lenovo Yoga Book X91F / X91L */
13662306a36Sopenharmony_ci		.matches = {
13762306a36Sopenharmony_ci			/* Non exact match to match F + L versions */
13862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
13962306a36Sopenharmony_ci		}
14062306a36Sopenharmony_ci	},
14162306a36Sopenharmony_ci#endif
14262306a36Sopenharmony_ci	{}
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/*
14662306a36Sopenharmony_ci * Those tablets have their x coordinate inverted
14762306a36Sopenharmony_ci */
14862306a36Sopenharmony_cistatic const struct dmi_system_id inverted_x_screen[] = {
14962306a36Sopenharmony_ci#if defined(CONFIG_DMI) && defined(CONFIG_X86)
15062306a36Sopenharmony_ci	{
15162306a36Sopenharmony_ci		.ident = "Cube I15-TC",
15262306a36Sopenharmony_ci		.matches = {
15362306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Cube"),
15462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "I15-TC")
15562306a36Sopenharmony_ci		},
15662306a36Sopenharmony_ci	},
15762306a36Sopenharmony_ci#endif
15862306a36Sopenharmony_ci	{}
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/**
16262306a36Sopenharmony_ci * goodix_i2c_read - read data from a register of the i2c slave device.
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci * @client: i2c device.
16562306a36Sopenharmony_ci * @reg: the register to read from.
16662306a36Sopenharmony_ci * @buf: raw write data buffer.
16762306a36Sopenharmony_ci * @len: length of the buffer to write
16862306a36Sopenharmony_ci */
16962306a36Sopenharmony_ciint goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct i2c_msg msgs[2];
17262306a36Sopenharmony_ci	__be16 wbuf = cpu_to_be16(reg);
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	msgs[0].flags = 0;
17662306a36Sopenharmony_ci	msgs[0].addr  = client->addr;
17762306a36Sopenharmony_ci	msgs[0].len   = 2;
17862306a36Sopenharmony_ci	msgs[0].buf   = (u8 *)&wbuf;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	msgs[1].flags = I2C_M_RD;
18162306a36Sopenharmony_ci	msgs[1].addr  = client->addr;
18262306a36Sopenharmony_ci	msgs[1].len   = len;
18362306a36Sopenharmony_ci	msgs[1].buf   = buf;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, 2);
18662306a36Sopenharmony_ci	if (ret >= 0)
18762306a36Sopenharmony_ci		ret = (ret == ARRAY_SIZE(msgs) ? 0 : -EIO);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	if (ret)
19062306a36Sopenharmony_ci		dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d\n",
19162306a36Sopenharmony_ci			len, reg, ret);
19262306a36Sopenharmony_ci	return ret;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/**
19662306a36Sopenharmony_ci * goodix_i2c_write - write data to a register of the i2c slave device.
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * @client: i2c device.
19962306a36Sopenharmony_ci * @reg: the register to write to.
20062306a36Sopenharmony_ci * @buf: raw data buffer to write.
20162306a36Sopenharmony_ci * @len: length of the buffer to write
20262306a36Sopenharmony_ci */
20362306a36Sopenharmony_ciint goodix_i2c_write(struct i2c_client *client, u16 reg, const u8 *buf, int len)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	u8 *addr_buf;
20662306a36Sopenharmony_ci	struct i2c_msg msg;
20762306a36Sopenharmony_ci	int ret;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	addr_buf = kmalloc(len + 2, GFP_KERNEL);
21062306a36Sopenharmony_ci	if (!addr_buf)
21162306a36Sopenharmony_ci		return -ENOMEM;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	addr_buf[0] = reg >> 8;
21462306a36Sopenharmony_ci	addr_buf[1] = reg & 0xFF;
21562306a36Sopenharmony_ci	memcpy(&addr_buf[2], buf, len);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	msg.flags = 0;
21862306a36Sopenharmony_ci	msg.addr = client->addr;
21962306a36Sopenharmony_ci	msg.buf = addr_buf;
22062306a36Sopenharmony_ci	msg.len = len + 2;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ret = i2c_transfer(client->adapter, &msg, 1);
22362306a36Sopenharmony_ci	if (ret >= 0)
22462306a36Sopenharmony_ci		ret = (ret == 1 ? 0 : -EIO);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	kfree(addr_buf);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (ret)
22962306a36Sopenharmony_ci		dev_err(&client->dev, "Error writing %d bytes to 0x%04x: %d\n",
23062306a36Sopenharmony_ci			len, reg, ret);
23162306a36Sopenharmony_ci	return ret;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ciint goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	return goodix_i2c_write(client, reg, &value, sizeof(value));
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic const struct goodix_chip_data *goodix_get_chip_data(const char *id)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	unsigned int i;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	for (i = 0; goodix_chip_ids[i].id; i++) {
24462306a36Sopenharmony_ci		if (!strcmp(goodix_chip_ids[i].id, id))
24562306a36Sopenharmony_ci			return goodix_chip_ids[i].data;
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return &gt9x_chip_data;
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	unsigned long max_timeout;
25462306a36Sopenharmony_ci	int touch_num;
25562306a36Sopenharmony_ci	int error;
25662306a36Sopenharmony_ci	u16 addr = GOODIX_READ_COOR_ADDR;
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * We are going to read 1-byte header,
25962306a36Sopenharmony_ci	 * ts->contact_size * max(1, touch_num) bytes of coordinates
26062306a36Sopenharmony_ci	 * and 1-byte footer which contains the touch-key code.
26162306a36Sopenharmony_ci	 */
26262306a36Sopenharmony_ci	const int header_contact_keycode_size = 1 + ts->contact_size + 1;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	/*
26562306a36Sopenharmony_ci	 * The 'buffer status' bit, which indicates that the data is valid, is
26662306a36Sopenharmony_ci	 * not set as soon as the interrupt is raised, but slightly after.
26762306a36Sopenharmony_ci	 * This takes around 10 ms to happen, so we poll for 20 ms.
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
27062306a36Sopenharmony_ci	do {
27162306a36Sopenharmony_ci		error = goodix_i2c_read(ts->client, addr, data,
27262306a36Sopenharmony_ci					header_contact_keycode_size);
27362306a36Sopenharmony_ci		if (error)
27462306a36Sopenharmony_ci			return error;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		if (data[0] & GOODIX_BUFFER_STATUS_READY) {
27762306a36Sopenharmony_ci			touch_num = data[0] & 0x0f;
27862306a36Sopenharmony_ci			if (touch_num > ts->max_touch_num)
27962306a36Sopenharmony_ci				return -EPROTO;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci			if (touch_num > 1) {
28262306a36Sopenharmony_ci				addr += header_contact_keycode_size;
28362306a36Sopenharmony_ci				data += header_contact_keycode_size;
28462306a36Sopenharmony_ci				error = goodix_i2c_read(ts->client,
28562306a36Sopenharmony_ci						addr, data,
28662306a36Sopenharmony_ci						ts->contact_size *
28762306a36Sopenharmony_ci							(touch_num - 1));
28862306a36Sopenharmony_ci				if (error)
28962306a36Sopenharmony_ci					return error;
29062306a36Sopenharmony_ci			}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci			return touch_num;
29362306a36Sopenharmony_ci		}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		if (data[0] == 0 && ts->firmware_name) {
29662306a36Sopenharmony_ci			if (goodix_handle_fw_request(ts))
29762306a36Sopenharmony_ci				return 0;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
30162306a36Sopenharmony_ci	} while (time_before(jiffies, max_timeout));
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/*
30462306a36Sopenharmony_ci	 * The Goodix panel will send spurious interrupts after a
30562306a36Sopenharmony_ci	 * 'finger up' event, which will always cause a timeout.
30662306a36Sopenharmony_ci	 */
30762306a36Sopenharmony_ci	return -ENOMSG;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int goodix_create_pen_input(struct goodix_ts_data *ts)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct device *dev = &ts->client->dev;
31362306a36Sopenharmony_ci	struct input_dev *input;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	input = devm_input_allocate_device(dev);
31662306a36Sopenharmony_ci	if (!input)
31762306a36Sopenharmony_ci		return -ENOMEM;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	input_copy_abs(input, ABS_X, ts->input_dev, ABS_MT_POSITION_X);
32062306a36Sopenharmony_ci	input_copy_abs(input, ABS_Y, ts->input_dev, ABS_MT_POSITION_Y);
32162306a36Sopenharmony_ci	/*
32262306a36Sopenharmony_ci	 * The resolution of these touchscreens is about 10 units/mm, the actual
32362306a36Sopenharmony_ci	 * resolution does not matter much since we set INPUT_PROP_DIRECT.
32462306a36Sopenharmony_ci	 * Userspace wants something here though, so just set it to 10 units/mm.
32562306a36Sopenharmony_ci	 */
32662306a36Sopenharmony_ci	input_abs_set_res(input, ABS_X, 10);
32762306a36Sopenharmony_ci	input_abs_set_res(input, ABS_Y, 10);
32862306a36Sopenharmony_ci	input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, BTN_TOUCH);
33162306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
33262306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, BTN_STYLUS);
33362306a36Sopenharmony_ci	input_set_capability(input, EV_KEY, BTN_STYLUS2);
33462306a36Sopenharmony_ci	__set_bit(INPUT_PROP_DIRECT, input->propbit);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	input->name = "Goodix Active Pen";
33762306a36Sopenharmony_ci	input->phys = "input/pen";
33862306a36Sopenharmony_ci	input->id.bustype = BUS_I2C;
33962306a36Sopenharmony_ci	input->id.vendor = 0x0416;
34062306a36Sopenharmony_ci	if (kstrtou16(ts->id, 10, &input->id.product))
34162306a36Sopenharmony_ci		input->id.product = 0x1001;
34262306a36Sopenharmony_ci	input->id.version = ts->version;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	ts->input_pen = input;
34562306a36Sopenharmony_ci	return 0;
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistatic void goodix_ts_report_pen_down(struct goodix_ts_data *ts, u8 *data)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int input_x, input_y, input_w, error;
35162306a36Sopenharmony_ci	u8 key_value;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (!ts->pen_input_registered) {
35462306a36Sopenharmony_ci		error = input_register_device(ts->input_pen);
35562306a36Sopenharmony_ci		ts->pen_input_registered = (error == 0) ? 1 : error;
35662306a36Sopenharmony_ci	}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (ts->pen_input_registered < 0)
35962306a36Sopenharmony_ci		return;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (ts->contact_size == 9) {
36262306a36Sopenharmony_ci		input_x = get_unaligned_le16(&data[4]);
36362306a36Sopenharmony_ci		input_y = get_unaligned_le16(&data[6]);
36462306a36Sopenharmony_ci		input_w = get_unaligned_le16(&data[8]);
36562306a36Sopenharmony_ci	} else {
36662306a36Sopenharmony_ci		input_x = get_unaligned_le16(&data[2]);
36762306a36Sopenharmony_ci		input_y = get_unaligned_le16(&data[4]);
36862306a36Sopenharmony_ci		input_w = get_unaligned_le16(&data[6]);
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	touchscreen_report_pos(ts->input_pen, &ts->prop, input_x, input_y, false);
37262306a36Sopenharmony_ci	input_report_abs(ts->input_pen, ABS_PRESSURE, input_w);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_TOUCH, 1);
37562306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_TOOL_PEN, 1);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (data[0] & GOODIX_HAVE_KEY) {
37862306a36Sopenharmony_ci		key_value = data[1 + ts->contact_size];
37962306a36Sopenharmony_ci		input_report_key(ts->input_pen, BTN_STYLUS, key_value & 0x10);
38062306a36Sopenharmony_ci		input_report_key(ts->input_pen, BTN_STYLUS2, key_value & 0x20);
38162306a36Sopenharmony_ci	} else {
38262306a36Sopenharmony_ci		input_report_key(ts->input_pen, BTN_STYLUS, 0);
38362306a36Sopenharmony_ci		input_report_key(ts->input_pen, BTN_STYLUS2, 0);
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	input_sync(ts->input_pen);
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void goodix_ts_report_pen_up(struct goodix_ts_data *ts)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	if (!ts->input_pen)
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_TOUCH, 0);
39562306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_TOOL_PEN, 0);
39662306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_STYLUS, 0);
39762306a36Sopenharmony_ci	input_report_key(ts->input_pen, BTN_STYLUS2, 0);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	input_sync(ts->input_pen);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	int id = coor_data[0] & 0x0F;
40562306a36Sopenharmony_ci	int input_x = get_unaligned_le16(&coor_data[1]);
40662306a36Sopenharmony_ci	int input_y = get_unaligned_le16(&coor_data[3]);
40762306a36Sopenharmony_ci	int input_w = get_unaligned_le16(&coor_data[5]);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	input_mt_slot(ts->input_dev, id);
41062306a36Sopenharmony_ci	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
41162306a36Sopenharmony_ci	touchscreen_report_pos(ts->input_dev, &ts->prop,
41262306a36Sopenharmony_ci			       input_x, input_y, true);
41362306a36Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
41462306a36Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	int id = coor_data[1] & 0x0F;
42062306a36Sopenharmony_ci	int input_x = get_unaligned_le16(&coor_data[3]);
42162306a36Sopenharmony_ci	int input_y = get_unaligned_le16(&coor_data[5]);
42262306a36Sopenharmony_ci	int input_w = get_unaligned_le16(&coor_data[7]);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	input_mt_slot(ts->input_dev, id);
42562306a36Sopenharmony_ci	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
42662306a36Sopenharmony_ci	touchscreen_report_pos(ts->input_dev, &ts->prop,
42762306a36Sopenharmony_ci			       input_x, input_y, true);
42862306a36Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
42962306a36Sopenharmony_ci	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic void goodix_ts_release_keys(struct goodix_ts_data *ts)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	int i;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	for (i = 0; i < GOODIX_MAX_KEYS; i++)
43762306a36Sopenharmony_ci		input_report_key(ts->input_dev, ts->keymap[i], 0);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	int touch_num;
44362306a36Sopenharmony_ci	u8 key_value;
44462306a36Sopenharmony_ci	int i;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	if (data[0] & GOODIX_HAVE_KEY) {
44762306a36Sopenharmony_ci		touch_num = data[0] & 0x0f;
44862306a36Sopenharmony_ci		key_value = data[1 + ts->contact_size * touch_num];
44962306a36Sopenharmony_ci		for (i = 0; i < GOODIX_MAX_KEYS; i++)
45062306a36Sopenharmony_ci			if (key_value & BIT(i))
45162306a36Sopenharmony_ci				input_report_key(ts->input_dev,
45262306a36Sopenharmony_ci						 ts->keymap[i], 1);
45362306a36Sopenharmony_ci	} else {
45462306a36Sopenharmony_ci		goodix_ts_release_keys(ts);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/**
45962306a36Sopenharmony_ci * goodix_process_events - Process incoming events
46062306a36Sopenharmony_ci *
46162306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer
46262306a36Sopenharmony_ci *
46362306a36Sopenharmony_ci * Called when the IRQ is triggered. Read the current device state, and push
46462306a36Sopenharmony_ci * the input events to the user space.
46562306a36Sopenharmony_ci */
46662306a36Sopenharmony_cistatic void goodix_process_events(struct goodix_ts_data *ts)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	u8  point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
46962306a36Sopenharmony_ci	int touch_num;
47062306a36Sopenharmony_ci	int i;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	touch_num = goodix_ts_read_input_report(ts, point_data);
47362306a36Sopenharmony_ci	if (touch_num < 0)
47462306a36Sopenharmony_ci		return;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* The pen being down is always reported as a single touch */
47762306a36Sopenharmony_ci	if (touch_num == 1 && (point_data[1] & 0x80)) {
47862306a36Sopenharmony_ci		goodix_ts_report_pen_down(ts, point_data);
47962306a36Sopenharmony_ci		goodix_ts_release_keys(ts);
48062306a36Sopenharmony_ci		goto sync; /* Release any previously registered touches */
48162306a36Sopenharmony_ci	} else {
48262306a36Sopenharmony_ci		goodix_ts_report_pen_up(ts);
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	goodix_ts_report_key(ts, point_data);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	for (i = 0; i < touch_num; i++)
48862306a36Sopenharmony_ci		if (ts->contact_size == 9)
48962306a36Sopenharmony_ci			goodix_ts_report_touch_9b(ts,
49062306a36Sopenharmony_ci				&point_data[1 + ts->contact_size * i]);
49162306a36Sopenharmony_ci		else
49262306a36Sopenharmony_ci			goodix_ts_report_touch_8b(ts,
49362306a36Sopenharmony_ci				&point_data[1 + ts->contact_size * i]);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cisync:
49662306a36Sopenharmony_ci	input_mt_sync_frame(ts->input_dev);
49762306a36Sopenharmony_ci	input_sync(ts->input_dev);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci/**
50162306a36Sopenharmony_ci * goodix_ts_irq_handler - The IRQ handler
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * @irq: interrupt number.
50462306a36Sopenharmony_ci * @dev_id: private data pointer.
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct goodix_ts_data *ts = dev_id;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	goodix_process_events(ts);
51162306a36Sopenharmony_ci	goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	return IRQ_HANDLED;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void goodix_free_irq(struct goodix_ts_data *ts)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	devm_free_irq(&ts->client->dev, ts->client->irq, ts);
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic int goodix_request_irq(struct goodix_ts_data *ts)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
52462306a36Sopenharmony_ci					 NULL, goodix_ts_irq_handler,
52562306a36Sopenharmony_ci					 ts->irq_flags, ts->client->name, ts);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int i, raw_cfg_len = len - 2;
53162306a36Sopenharmony_ci	u8 check_sum = 0;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i++)
53462306a36Sopenharmony_ci		check_sum += cfg[i];
53562306a36Sopenharmony_ci	check_sum = (~check_sum) + 1;
53662306a36Sopenharmony_ci	if (check_sum != cfg[raw_cfg_len]) {
53762306a36Sopenharmony_ci		dev_err(&ts->client->dev,
53862306a36Sopenharmony_ci			"The checksum of the config fw is not correct");
53962306a36Sopenharmony_ci		return -EINVAL;
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (cfg[raw_cfg_len + 1] != 1) {
54362306a36Sopenharmony_ci		dev_err(&ts->client->dev,
54462306a36Sopenharmony_ci			"Config fw must have Config_Fresh register set");
54562306a36Sopenharmony_ci		return -EINVAL;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_8(struct goodix_ts_data *ts)
55262306a36Sopenharmony_ci{
55362306a36Sopenharmony_ci	int i, raw_cfg_len = ts->chip->config_len - 2;
55462306a36Sopenharmony_ci	u8 check_sum = 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i++)
55762306a36Sopenharmony_ci		check_sum += ts->config[i];
55862306a36Sopenharmony_ci	check_sum = (~check_sum) + 1;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ts->config[raw_cfg_len] = check_sum;
56162306a36Sopenharmony_ci	ts->config[raw_cfg_len + 1] = 1; /* Set "config_fresh" bit */
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int goodix_check_cfg_16(struct goodix_ts_data *ts, const u8 *cfg,
56562306a36Sopenharmony_ci			       int len)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	int i, raw_cfg_len = len - 3;
56862306a36Sopenharmony_ci	u16 check_sum = 0;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i += 2)
57162306a36Sopenharmony_ci		check_sum += get_unaligned_be16(&cfg[i]);
57262306a36Sopenharmony_ci	check_sum = (~check_sum) + 1;
57362306a36Sopenharmony_ci	if (check_sum != get_unaligned_be16(&cfg[raw_cfg_len])) {
57462306a36Sopenharmony_ci		dev_err(&ts->client->dev,
57562306a36Sopenharmony_ci			"The checksum of the config fw is not correct");
57662306a36Sopenharmony_ci		return -EINVAL;
57762306a36Sopenharmony_ci	}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (cfg[raw_cfg_len + 2] != 1) {
58062306a36Sopenharmony_ci		dev_err(&ts->client->dev,
58162306a36Sopenharmony_ci			"Config fw must have Config_Fresh register set");
58262306a36Sopenharmony_ci		return -EINVAL;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic void goodix_calc_cfg_checksum_16(struct goodix_ts_data *ts)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	int i, raw_cfg_len = ts->chip->config_len - 3;
59162306a36Sopenharmony_ci	u16 check_sum = 0;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	for (i = 0; i < raw_cfg_len; i += 2)
59462306a36Sopenharmony_ci		check_sum += get_unaligned_be16(&ts->config[i]);
59562306a36Sopenharmony_ci	check_sum = (~check_sum) + 1;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	put_unaligned_be16(check_sum, &ts->config[raw_cfg_len]);
59862306a36Sopenharmony_ci	ts->config[raw_cfg_len + 2] = 1; /* Set "config_fresh" bit */
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci/**
60262306a36Sopenharmony_ci * goodix_check_cfg - Checks if config fw is valid
60362306a36Sopenharmony_ci *
60462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer
60562306a36Sopenharmony_ci * @cfg: firmware config data
60662306a36Sopenharmony_ci * @len: config data length
60762306a36Sopenharmony_ci */
60862306a36Sopenharmony_cistatic int goodix_check_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	if (len < GOODIX_CONFIG_MIN_LENGTH ||
61162306a36Sopenharmony_ci	    len > GOODIX_CONFIG_MAX_LENGTH) {
61262306a36Sopenharmony_ci		dev_err(&ts->client->dev,
61362306a36Sopenharmony_ci			"The length of the config fw is not correct");
61462306a36Sopenharmony_ci		return -EINVAL;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return ts->chip->check_config(ts, cfg, len);
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/**
62162306a36Sopenharmony_ci * goodix_send_cfg - Write fw config to device
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci * @ts: goodix_ts_data pointer
62462306a36Sopenharmony_ci * @cfg: config firmware to write to device
62562306a36Sopenharmony_ci * @len: config data length
62662306a36Sopenharmony_ci */
62762306a36Sopenharmony_ciint goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	int error;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	error = goodix_check_cfg(ts, cfg, len);
63262306a36Sopenharmony_ci	if (error)
63362306a36Sopenharmony_ci		return error;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg, len);
63662306a36Sopenharmony_ci	if (error)
63762306a36Sopenharmony_ci		return error;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	dev_dbg(&ts->client->dev, "Config sent successfully.");
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	/* Let the firmware reconfigure itself, so sleep for 10ms */
64262306a36Sopenharmony_ci	usleep_range(10000, 11000);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	return 0;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT
64862306a36Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
65162306a36Sopenharmony_ci	acpi_status status;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	status = acpi_evaluate_object(handle, "INTI", NULL, NULL);
65462306a36Sopenharmony_ci	return ACPI_SUCCESS(status) ? 0 : -EIO;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	acpi_handle handle = ACPI_HANDLE(&ts->client->dev);
66062306a36Sopenharmony_ci	acpi_status status;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	status = acpi_execute_simple_method(handle, "INTO", value);
66362306a36Sopenharmony_ci	return ACPI_SUCCESS(status) ? 0 : -EIO;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci#else
66662306a36Sopenharmony_cistatic int goodix_pin_acpi_direction_input(struct goodix_ts_data *ts)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	dev_err(&ts->client->dev,
66962306a36Sopenharmony_ci		"%s called on device without ACPI support\n", __func__);
67062306a36Sopenharmony_ci	return -EINVAL;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int goodix_pin_acpi_output_method(struct goodix_ts_data *ts, int value)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	dev_err(&ts->client->dev,
67662306a36Sopenharmony_ci		"%s called on device without ACPI support\n", __func__);
67762306a36Sopenharmony_ci	return -EINVAL;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci#endif
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic int goodix_irq_direction_output(struct goodix_ts_data *ts, int value)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	switch (ts->irq_pin_access_method) {
68462306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_NONE:
68562306a36Sopenharmony_ci		dev_err(&ts->client->dev,
68662306a36Sopenharmony_ci			"%s called without an irq_pin_access_method set\n",
68762306a36Sopenharmony_ci			__func__);
68862306a36Sopenharmony_ci		return -EINVAL;
68962306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_GPIO:
69062306a36Sopenharmony_ci		return gpiod_direction_output(ts->gpiod_int, value);
69162306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
69262306a36Sopenharmony_ci		/*
69362306a36Sopenharmony_ci		 * The IRQ pin triggers on a falling edge, so its gets marked
69462306a36Sopenharmony_ci		 * as active-low, use output_raw to avoid the value inversion.
69562306a36Sopenharmony_ci		 */
69662306a36Sopenharmony_ci		return gpiod_direction_output_raw(ts->gpiod_int, value);
69762306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
69862306a36Sopenharmony_ci		return goodix_pin_acpi_output_method(ts, value);
69962306a36Sopenharmony_ci	}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	return -EINVAL; /* Never reached */
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic int goodix_irq_direction_input(struct goodix_ts_data *ts)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	switch (ts->irq_pin_access_method) {
70762306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_NONE:
70862306a36Sopenharmony_ci		dev_err(&ts->client->dev,
70962306a36Sopenharmony_ci			"%s called without an irq_pin_access_method set\n",
71062306a36Sopenharmony_ci			__func__);
71162306a36Sopenharmony_ci		return -EINVAL;
71262306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_GPIO:
71362306a36Sopenharmony_ci		return gpiod_direction_input(ts->gpiod_int);
71462306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
71562306a36Sopenharmony_ci		return gpiod_direction_input(ts->gpiod_int);
71662306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
71762306a36Sopenharmony_ci		return goodix_pin_acpi_direction_input(ts);
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return -EINVAL; /* Never reached */
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ciint goodix_int_sync(struct goodix_ts_data *ts)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int error;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	error = goodix_irq_direction_output(ts, 0);
72862306a36Sopenharmony_ci	if (error)
72962306a36Sopenharmony_ci		goto error;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	msleep(50);				/* T5: 50ms */
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	error = goodix_irq_direction_input(ts);
73462306a36Sopenharmony_ci	if (error)
73562306a36Sopenharmony_ci		goto error;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	return 0;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cierror:
74062306a36Sopenharmony_ci	dev_err(&ts->client->dev, "Controller irq sync failed.\n");
74162306a36Sopenharmony_ci	return error;
74262306a36Sopenharmony_ci}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci/**
74562306a36Sopenharmony_ci * goodix_reset_no_int_sync - Reset device, leaving interrupt line in output mode
74662306a36Sopenharmony_ci *
74762306a36Sopenharmony_ci * @ts: goodix_ts_data pointer
74862306a36Sopenharmony_ci */
74962306a36Sopenharmony_ciint goodix_reset_no_int_sync(struct goodix_ts_data *ts)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	int error;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	/* begin select I2C slave addr */
75462306a36Sopenharmony_ci	error = gpiod_direction_output(ts->gpiod_rst, 0);
75562306a36Sopenharmony_ci	if (error)
75662306a36Sopenharmony_ci		goto error;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	msleep(20);				/* T2: > 10ms */
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */
76162306a36Sopenharmony_ci	error = goodix_irq_direction_output(ts, ts->client->addr == 0x14);
76262306a36Sopenharmony_ci	if (error)
76362306a36Sopenharmony_ci		goto error;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	usleep_range(100, 2000);		/* T3: > 100us */
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	error = gpiod_direction_output(ts->gpiod_rst, 1);
76862306a36Sopenharmony_ci	if (error)
76962306a36Sopenharmony_ci		goto error;
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	usleep_range(6000, 10000);		/* T4: > 5ms */
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/*
77462306a36Sopenharmony_ci	 * Put the reset pin back in to input / high-impedance mode to save
77562306a36Sopenharmony_ci	 * power. Only do this in the non ACPI case since some ACPI boards
77662306a36Sopenharmony_ci	 * don't have a pull-up, so there the reset pin must stay active-high.
77762306a36Sopenharmony_ci	 */
77862306a36Sopenharmony_ci	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
77962306a36Sopenharmony_ci		error = gpiod_direction_input(ts->gpiod_rst);
78062306a36Sopenharmony_ci		if (error)
78162306a36Sopenharmony_ci			goto error;
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cierror:
78762306a36Sopenharmony_ci	dev_err(&ts->client->dev, "Controller reset failed.\n");
78862306a36Sopenharmony_ci	return error;
78962306a36Sopenharmony_ci}
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci/**
79262306a36Sopenharmony_ci * goodix_reset - Reset device during power on
79362306a36Sopenharmony_ci *
79462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer
79562306a36Sopenharmony_ci */
79662306a36Sopenharmony_cistatic int goodix_reset(struct goodix_ts_data *ts)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	int error;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	error = goodix_reset_no_int_sync(ts);
80162306a36Sopenharmony_ci	if (error)
80262306a36Sopenharmony_ci		return error;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return goodix_int_sync(ts);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci#ifdef ACPI_GPIO_SUPPORT
80862306a36Sopenharmony_cistatic const struct acpi_gpio_params first_gpio = { 0, 0, false };
80962306a36Sopenharmony_cistatic const struct acpi_gpio_params second_gpio = { 1, 0, false };
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_first_gpios[] = {
81262306a36Sopenharmony_ci	{ GOODIX_GPIO_INT_NAME "-gpios", &first_gpio, 1 },
81362306a36Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &second_gpio, 1 },
81462306a36Sopenharmony_ci	{ },
81562306a36Sopenharmony_ci};
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_int_last_gpios[] = {
81862306a36Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
81962306a36Sopenharmony_ci	{ GOODIX_GPIO_INT_NAME "-gpios", &second_gpio, 1 },
82062306a36Sopenharmony_ci	{ },
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const struct acpi_gpio_mapping acpi_goodix_reset_only_gpios[] = {
82462306a36Sopenharmony_ci	{ GOODIX_GPIO_RST_NAME "-gpios", &first_gpio, 1 },
82562306a36Sopenharmony_ci	{ },
82662306a36Sopenharmony_ci};
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic int goodix_resource(struct acpi_resource *ares, void *data)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	struct goodix_ts_data *ts = data;
83162306a36Sopenharmony_ci	struct device *dev = &ts->client->dev;
83262306a36Sopenharmony_ci	struct acpi_resource_gpio *gpio;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	if (acpi_gpio_get_irq_resource(ares, &gpio)) {
83562306a36Sopenharmony_ci		if (ts->gpio_int_idx == -1) {
83662306a36Sopenharmony_ci			ts->gpio_int_idx = ts->gpio_count;
83762306a36Sopenharmony_ci		} else {
83862306a36Sopenharmony_ci			dev_err(dev, "More then one GpioInt resource, ignoring ACPI GPIO resources\n");
83962306a36Sopenharmony_ci			ts->gpio_int_idx = -2;
84062306a36Sopenharmony_ci		}
84162306a36Sopenharmony_ci		ts->gpio_count++;
84262306a36Sopenharmony_ci	} else if (acpi_gpio_get_io_resource(ares, &gpio))
84362306a36Sopenharmony_ci		ts->gpio_count++;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return 0;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci/*
84962306a36Sopenharmony_ci * This function gets called in case we fail to get the irq GPIO directly
85062306a36Sopenharmony_ci * because the ACPI tables lack GPIO-name to APCI _CRS index mappings
85162306a36Sopenharmony_ci * (no _DSD UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 data).
85262306a36Sopenharmony_ci * In that case we add our own mapping and then goodix_get_gpio_config()
85362306a36Sopenharmony_ci * retries to get the GPIOs based on the added mapping.
85462306a36Sopenharmony_ci */
85562306a36Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	const struct acpi_gpio_mapping *gpio_mapping = NULL;
85862306a36Sopenharmony_ci	struct device *dev = &ts->client->dev;
85962306a36Sopenharmony_ci	LIST_HEAD(resources);
86062306a36Sopenharmony_ci	int irq, ret;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	ts->gpio_count = 0;
86362306a36Sopenharmony_ci	ts->gpio_int_idx = -1;
86462306a36Sopenharmony_ci	ret = acpi_dev_get_resources(ACPI_COMPANION(dev), &resources,
86562306a36Sopenharmony_ci				     goodix_resource, ts);
86662306a36Sopenharmony_ci	if (ret < 0) {
86762306a36Sopenharmony_ci		dev_err(dev, "Error getting ACPI resources: %d\n", ret);
86862306a36Sopenharmony_ci		return ret;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	acpi_dev_free_resource_list(&resources);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	/*
87462306a36Sopenharmony_ci	 * CHT devices should have a GpioInt + a regular GPIO ACPI resource.
87562306a36Sopenharmony_ci	 * Some CHT devices have a bug (where the also is bogus Interrupt
87662306a36Sopenharmony_ci	 * resource copied from a previous BYT based generation). i2c-core-acpi
87762306a36Sopenharmony_ci	 * will use the non-working Interrupt resource, fix this up.
87862306a36Sopenharmony_ci	 */
87962306a36Sopenharmony_ci	if (soc_intel_is_cht() && ts->gpio_count == 2 && ts->gpio_int_idx != -1) {
88062306a36Sopenharmony_ci		irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
88162306a36Sopenharmony_ci		if (irq > 0 && irq != ts->client->irq) {
88262306a36Sopenharmony_ci			dev_warn(dev, "Overriding IRQ %d -> %d\n", ts->client->irq, irq);
88362306a36Sopenharmony_ci			ts->client->irq = irq;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Some devices with gpio_int_idx 0 list a third unused GPIO */
88862306a36Sopenharmony_ci	if ((ts->gpio_count == 2 || ts->gpio_count == 3) && ts->gpio_int_idx == 0) {
88962306a36Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
89062306a36Sopenharmony_ci		gpio_mapping = acpi_goodix_int_first_gpios;
89162306a36Sopenharmony_ci	} else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) {
89262306a36Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
89362306a36Sopenharmony_ci		gpio_mapping = acpi_goodix_int_last_gpios;
89462306a36Sopenharmony_ci	} else if (ts->gpio_count == 1 && ts->gpio_int_idx == -1 &&
89562306a36Sopenharmony_ci		   acpi_has_method(ACPI_HANDLE(dev), "INTI") &&
89662306a36Sopenharmony_ci		   acpi_has_method(ACPI_HANDLE(dev), "INTO")) {
89762306a36Sopenharmony_ci		dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n");
89862306a36Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD;
89962306a36Sopenharmony_ci		gpio_mapping = acpi_goodix_reset_only_gpios;
90062306a36Sopenharmony_ci	} else if (soc_intel_is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
90162306a36Sopenharmony_ci		dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
90262306a36Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
90362306a36Sopenharmony_ci		gpio_mapping = acpi_goodix_int_last_gpios;
90462306a36Sopenharmony_ci	} else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) {
90562306a36Sopenharmony_ci		/*
90662306a36Sopenharmony_ci		 * On newer devices there is only 1 GpioInt resource and _PS0
90762306a36Sopenharmony_ci		 * does the whole reset sequence for us.
90862306a36Sopenharmony_ci		 */
90962306a36Sopenharmony_ci		acpi_device_fix_up_power(ACPI_COMPANION(dev));
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci		/*
91262306a36Sopenharmony_ci		 * Before the _PS0 call the int GPIO may have been in output
91362306a36Sopenharmony_ci		 * mode and the call should have put the int GPIO in input mode,
91462306a36Sopenharmony_ci		 * but the GPIO subsys cached state may still think it is
91562306a36Sopenharmony_ci		 * in output mode, causing gpiochip_lock_as_irq() failure.
91662306a36Sopenharmony_ci		 *
91762306a36Sopenharmony_ci		 * Add a mapping for the int GPIO to make the
91862306a36Sopenharmony_ci		 * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed,
91962306a36Sopenharmony_ci		 * which will explicitly set the direction to input.
92062306a36Sopenharmony_ci		 */
92162306a36Sopenharmony_ci		ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
92262306a36Sopenharmony_ci		gpio_mapping = acpi_goodix_int_first_gpios;
92362306a36Sopenharmony_ci	} else {
92462306a36Sopenharmony_ci		dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
92562306a36Sopenharmony_ci			 ts->gpio_count, ts->gpio_int_idx);
92662306a36Sopenharmony_ci		/*
92762306a36Sopenharmony_ci		 * On some devices _PS0 does a reset for us and
92862306a36Sopenharmony_ci		 * sometimes this is necessary for things to work.
92962306a36Sopenharmony_ci		 */
93062306a36Sopenharmony_ci		acpi_device_fix_up_power(ACPI_COMPANION(dev));
93162306a36Sopenharmony_ci		return -EINVAL;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/*
93562306a36Sopenharmony_ci	 * Normally we put the reset pin in input / high-impedance mode to save
93662306a36Sopenharmony_ci	 * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
93762306a36Sopenharmony_ci	 * case, leave the pin as is. This results in the pin not being touched
93862306a36Sopenharmony_ci	 * at all on x86/ACPI boards, except when needed for error-recover.
93962306a36Sopenharmony_ci	 */
94062306a36Sopenharmony_ci	ts->gpiod_rst_flags = GPIOD_ASIS;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
94362306a36Sopenharmony_ci}
94462306a36Sopenharmony_ci#else
94562306a36Sopenharmony_cistatic int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	return -EINVAL;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci#endif /* CONFIG_X86 && CONFIG_ACPI */
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci/**
95262306a36Sopenharmony_ci * goodix_get_gpio_config - Get GPIO config from ACPI/DT
95362306a36Sopenharmony_ci *
95462306a36Sopenharmony_ci * @ts: goodix_ts_data pointer
95562306a36Sopenharmony_ci */
95662306a36Sopenharmony_cistatic int goodix_get_gpio_config(struct goodix_ts_data *ts)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	struct device *dev;
95962306a36Sopenharmony_ci	struct gpio_desc *gpiod;
96062306a36Sopenharmony_ci	bool added_acpi_mappings = false;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	if (!ts->client)
96362306a36Sopenharmony_ci		return -EINVAL;
96462306a36Sopenharmony_ci	dev = &ts->client->dev;
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	/*
96762306a36Sopenharmony_ci	 * By default we request the reset pin as input, leaving it in
96862306a36Sopenharmony_ci	 * high-impedance when not resetting the controller to save power.
96962306a36Sopenharmony_ci	 */
97062306a36Sopenharmony_ci	ts->gpiod_rst_flags = GPIOD_IN;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	ts->avdd28 = devm_regulator_get(dev, "AVDD28");
97362306a36Sopenharmony_ci	if (IS_ERR(ts->avdd28))
97462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n");
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	ts->vddio = devm_regulator_get(dev, "VDDIO");
97762306a36Sopenharmony_ci	if (IS_ERR(ts->vddio))
97862306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n");
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ciretry_get_irq_gpio:
98162306a36Sopenharmony_ci	/* Get the interrupt GPIO pin number */
98262306a36Sopenharmony_ci	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
98362306a36Sopenharmony_ci	if (IS_ERR(gpiod))
98462306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
98562306a36Sopenharmony_ci				     GOODIX_GPIO_INT_NAME);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) {
98862306a36Sopenharmony_ci		added_acpi_mappings = true;
98962306a36Sopenharmony_ci		if (goodix_add_acpi_gpio_mappings(ts) == 0)
99062306a36Sopenharmony_ci			goto retry_get_irq_gpio;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	ts->gpiod_int = gpiod;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* Get the reset line GPIO pin number */
99662306a36Sopenharmony_ci	gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
99762306a36Sopenharmony_ci	if (IS_ERR(gpiod))
99862306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
99962306a36Sopenharmony_ci				     GOODIX_GPIO_RST_NAME);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	ts->gpiod_rst = gpiod;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	switch (ts->irq_pin_access_method) {
100462306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_GPIO:
100562306a36Sopenharmony_ci		/*
100662306a36Sopenharmony_ci		 * We end up here if goodix_add_acpi_gpio_mappings() has
100762306a36Sopenharmony_ci		 * called devm_acpi_dev_add_driver_gpios() because the ACPI
100862306a36Sopenharmony_ci		 * tables did not contain name to index mappings.
100962306a36Sopenharmony_ci		 * Check that we successfully got both GPIOs after we've
101062306a36Sopenharmony_ci		 * added our own acpi_gpio_mapping and if we did not get both
101162306a36Sopenharmony_ci		 * GPIOs reset irq_pin_access_method to IRQ_PIN_ACCESS_NONE.
101262306a36Sopenharmony_ci		 */
101362306a36Sopenharmony_ci		if (!ts->gpiod_int || !ts->gpiod_rst)
101462306a36Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
101562306a36Sopenharmony_ci		break;
101662306a36Sopenharmony_ci	case IRQ_PIN_ACCESS_ACPI_METHOD:
101762306a36Sopenharmony_ci		if (!ts->gpiod_rst)
101862306a36Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
101962306a36Sopenharmony_ci		break;
102062306a36Sopenharmony_ci	default:
102162306a36Sopenharmony_ci		if (ts->gpiod_int && ts->gpiod_rst) {
102262306a36Sopenharmony_ci			ts->reset_controller_at_probe = true;
102362306a36Sopenharmony_ci			ts->load_cfg_from_disk = true;
102462306a36Sopenharmony_ci			ts->irq_pin_access_method = IRQ_PIN_ACCESS_GPIO;
102562306a36Sopenharmony_ci		}
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/**
103262306a36Sopenharmony_ci * goodix_read_config - Read the embedded configuration of the panel
103362306a36Sopenharmony_ci *
103462306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer
103562306a36Sopenharmony_ci *
103662306a36Sopenharmony_ci * Must be called during probe
103762306a36Sopenharmony_ci */
103862306a36Sopenharmony_cistatic void goodix_read_config(struct goodix_ts_data *ts)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	int x_max, y_max;
104162306a36Sopenharmony_ci	int error;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/*
104462306a36Sopenharmony_ci	 * On controllers where we need to upload the firmware
104562306a36Sopenharmony_ci	 * (controllers without flash) ts->config already has the config
104662306a36Sopenharmony_ci	 * at this point and the controller itself does not have it yet!
104762306a36Sopenharmony_ci	 */
104862306a36Sopenharmony_ci	if (!ts->firmware_name) {
104962306a36Sopenharmony_ci		error = goodix_i2c_read(ts->client, ts->chip->config_addr,
105062306a36Sopenharmony_ci					ts->config, ts->chip->config_len);
105162306a36Sopenharmony_ci		if (error) {
105262306a36Sopenharmony_ci			ts->int_trigger_type = GOODIX_INT_TRIGGER;
105362306a36Sopenharmony_ci			ts->max_touch_num = GOODIX_MAX_CONTACTS;
105462306a36Sopenharmony_ci			return;
105562306a36Sopenharmony_ci		}
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
105962306a36Sopenharmony_ci	ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]);
106262306a36Sopenharmony_ci	y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]);
106362306a36Sopenharmony_ci	if (x_max && y_max) {
106462306a36Sopenharmony_ci		input_abs_set_max(ts->input_dev, ABS_MT_POSITION_X, x_max - 1);
106562306a36Sopenharmony_ci		input_abs_set_max(ts->input_dev, ABS_MT_POSITION_Y, y_max - 1);
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	ts->chip->calc_config_checksum(ts);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/**
107262306a36Sopenharmony_ci * goodix_read_version - Read goodix touchscreen version
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_cistatic int goodix_read_version(struct goodix_ts_data *ts)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	int error;
107962306a36Sopenharmony_ci	u8 buf[6];
108062306a36Sopenharmony_ci	char id_str[GOODIX_ID_MAX_LEN + 1];
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	error = goodix_i2c_read(ts->client, GOODIX_REG_ID, buf, sizeof(buf));
108362306a36Sopenharmony_ci	if (error)
108462306a36Sopenharmony_ci		return error;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	memcpy(id_str, buf, GOODIX_ID_MAX_LEN);
108762306a36Sopenharmony_ci	id_str[GOODIX_ID_MAX_LEN] = 0;
108862306a36Sopenharmony_ci	strscpy(ts->id, id_str, GOODIX_ID_MAX_LEN + 1);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	ts->version = get_unaligned_le16(&buf[4]);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	dev_info(&ts->client->dev, "ID %s, version: %04x\n", ts->id,
109362306a36Sopenharmony_ci		 ts->version);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	return 0;
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci/**
109962306a36Sopenharmony_ci * goodix_i2c_test - I2C test function to check if the device answers.
110062306a36Sopenharmony_ci *
110162306a36Sopenharmony_ci * @client: the i2c client
110262306a36Sopenharmony_ci */
110362306a36Sopenharmony_cistatic int goodix_i2c_test(struct i2c_client *client)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	int retry = 0;
110662306a36Sopenharmony_ci	int error;
110762306a36Sopenharmony_ci	u8 test;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	while (retry++ < 2) {
111062306a36Sopenharmony_ci		error = goodix_i2c_read(client, GOODIX_REG_ID, &test, 1);
111162306a36Sopenharmony_ci		if (!error)
111262306a36Sopenharmony_ci			return 0;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		msleep(20);
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	return error;
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci/**
112162306a36Sopenharmony_ci * goodix_configure_dev - Finish device initialization
112262306a36Sopenharmony_ci *
112362306a36Sopenharmony_ci * @ts: our goodix_ts_data pointer
112462306a36Sopenharmony_ci *
112562306a36Sopenharmony_ci * Must be called from probe to finish initialization of the device.
112662306a36Sopenharmony_ci * Contains the common initialization code for both devices that
112762306a36Sopenharmony_ci * declare gpio pins and devices that do not. It is either called
112862306a36Sopenharmony_ci * directly from probe or from request_firmware_wait callback.
112962306a36Sopenharmony_ci */
113062306a36Sopenharmony_cistatic int goodix_configure_dev(struct goodix_ts_data *ts)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	int error;
113362306a36Sopenharmony_ci	int i;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	ts->int_trigger_type = GOODIX_INT_TRIGGER;
113662306a36Sopenharmony_ci	ts->max_touch_num = GOODIX_MAX_CONTACTS;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	ts->input_dev = devm_input_allocate_device(&ts->client->dev);
113962306a36Sopenharmony_ci	if (!ts->input_dev) {
114062306a36Sopenharmony_ci		dev_err(&ts->client->dev, "Failed to allocate input device.");
114162306a36Sopenharmony_ci		return -ENOMEM;
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ts->input_dev->name = "Goodix Capacitive TouchScreen";
114562306a36Sopenharmony_ci	ts->input_dev->phys = "input/ts";
114662306a36Sopenharmony_ci	ts->input_dev->id.bustype = BUS_I2C;
114762306a36Sopenharmony_ci	ts->input_dev->id.vendor = 0x0416;
114862306a36Sopenharmony_ci	if (kstrtou16(ts->id, 10, &ts->input_dev->id.product))
114962306a36Sopenharmony_ci		ts->input_dev->id.product = 0x1001;
115062306a36Sopenharmony_ci	ts->input_dev->id.version = ts->version;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	ts->input_dev->keycode = ts->keymap;
115362306a36Sopenharmony_ci	ts->input_dev->keycodesize = sizeof(ts->keymap[0]);
115462306a36Sopenharmony_ci	ts->input_dev->keycodemax = GOODIX_MAX_KEYS;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* Capacitive Windows/Home button on some devices */
115762306a36Sopenharmony_ci	for (i = 0; i < GOODIX_MAX_KEYS; ++i) {
115862306a36Sopenharmony_ci		if (i == 0)
115962306a36Sopenharmony_ci			ts->keymap[i] = KEY_LEFTMETA;
116062306a36Sopenharmony_ci		else
116162306a36Sopenharmony_ci			ts->keymap[i] = KEY_F1 + (i - 1);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		input_set_capability(ts->input_dev, EV_KEY, ts->keymap[i]);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
116762306a36Sopenharmony_ci	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
116862306a36Sopenharmony_ci	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
116962306a36Sopenharmony_ci	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ciretry_read_config:
117262306a36Sopenharmony_ci	/* Read configuration and apply touchscreen parameters */
117362306a36Sopenharmony_ci	goodix_read_config(ts);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Try overriding touchscreen parameters via device properties */
117662306a36Sopenharmony_ci	touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	if (!ts->prop.max_x || !ts->prop.max_y || !ts->max_touch_num) {
117962306a36Sopenharmony_ci		if (!ts->reset_controller_at_probe &&
118062306a36Sopenharmony_ci		    ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
118162306a36Sopenharmony_ci			dev_info(&ts->client->dev, "Config not set, resetting controller\n");
118262306a36Sopenharmony_ci			/* Retry after a controller reset */
118362306a36Sopenharmony_ci			ts->reset_controller_at_probe = true;
118462306a36Sopenharmony_ci			error = goodix_reset(ts);
118562306a36Sopenharmony_ci			if (error)
118662306a36Sopenharmony_ci				return error;
118762306a36Sopenharmony_ci			goto retry_read_config;
118862306a36Sopenharmony_ci		}
118962306a36Sopenharmony_ci		dev_err(&ts->client->dev,
119062306a36Sopenharmony_ci			"Invalid config (%d, %d, %d), using defaults\n",
119162306a36Sopenharmony_ci			ts->prop.max_x, ts->prop.max_y, ts->max_touch_num);
119262306a36Sopenharmony_ci		ts->prop.max_x = GOODIX_MAX_WIDTH - 1;
119362306a36Sopenharmony_ci		ts->prop.max_y = GOODIX_MAX_HEIGHT - 1;
119462306a36Sopenharmony_ci		ts->max_touch_num = GOODIX_MAX_CONTACTS;
119562306a36Sopenharmony_ci		input_abs_set_max(ts->input_dev,
119662306a36Sopenharmony_ci				  ABS_MT_POSITION_X, ts->prop.max_x);
119762306a36Sopenharmony_ci		input_abs_set_max(ts->input_dev,
119862306a36Sopenharmony_ci				  ABS_MT_POSITION_Y, ts->prop.max_y);
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (dmi_check_system(nine_bytes_report)) {
120262306a36Sopenharmony_ci		ts->contact_size = 9;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		dev_dbg(&ts->client->dev,
120562306a36Sopenharmony_ci			"Non-standard 9-bytes report format quirk\n");
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (dmi_check_system(inverted_x_screen)) {
120962306a36Sopenharmony_ci		ts->prop.invert_x = true;
121062306a36Sopenharmony_ci		dev_dbg(&ts->client->dev,
121162306a36Sopenharmony_ci			"Applying 'inverted x screen' quirk\n");
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
121562306a36Sopenharmony_ci				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
121662306a36Sopenharmony_ci	if (error) {
121762306a36Sopenharmony_ci		dev_err(&ts->client->dev,
121862306a36Sopenharmony_ci			"Failed to initialize MT slots: %d", error);
121962306a36Sopenharmony_ci		return error;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	error = input_register_device(ts->input_dev);
122362306a36Sopenharmony_ci	if (error) {
122462306a36Sopenharmony_ci		dev_err(&ts->client->dev,
122562306a36Sopenharmony_ci			"Failed to register input device: %d", error);
122662306a36Sopenharmony_ci		return error;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	/*
123062306a36Sopenharmony_ci	 * Create the input_pen device before goodix_request_irq() calls
123162306a36Sopenharmony_ci	 * devm_request_threaded_irq() so that the devm framework frees
123262306a36Sopenharmony_ci	 * it after disabling the irq.
123362306a36Sopenharmony_ci	 * Unfortunately there is no way to detect if the touchscreen has pen
123462306a36Sopenharmony_ci	 * support, so registering the dev is delayed till the first pen event.
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci	error = goodix_create_pen_input(ts);
123762306a36Sopenharmony_ci	if (error)
123862306a36Sopenharmony_ci		return error;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT;
124162306a36Sopenharmony_ci	error = goodix_request_irq(ts);
124262306a36Sopenharmony_ci	if (error) {
124362306a36Sopenharmony_ci		dev_err(&ts->client->dev, "request IRQ failed: %d\n", error);
124462306a36Sopenharmony_ci		return error;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/**
125162306a36Sopenharmony_ci * goodix_config_cb - Callback to finish device init
125262306a36Sopenharmony_ci *
125362306a36Sopenharmony_ci * @cfg: firmware config
125462306a36Sopenharmony_ci * @ctx: our goodix_ts_data pointer
125562306a36Sopenharmony_ci *
125662306a36Sopenharmony_ci * request_firmware_wait callback that finishes
125762306a36Sopenharmony_ci * initialization of the device.
125862306a36Sopenharmony_ci */
125962306a36Sopenharmony_cistatic void goodix_config_cb(const struct firmware *cfg, void *ctx)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	struct goodix_ts_data *ts = ctx;
126262306a36Sopenharmony_ci	int error;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	if (ts->firmware_name) {
126562306a36Sopenharmony_ci		if (!cfg)
126662306a36Sopenharmony_ci			goto err_release_cfg;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci		error = goodix_check_cfg(ts, cfg->data, cfg->size);
126962306a36Sopenharmony_ci		if (error)
127062306a36Sopenharmony_ci			goto err_release_cfg;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci		memcpy(ts->config, cfg->data, cfg->size);
127362306a36Sopenharmony_ci	} else if (cfg) {
127462306a36Sopenharmony_ci		/* send device configuration to the firmware */
127562306a36Sopenharmony_ci		error = goodix_send_cfg(ts, cfg->data, cfg->size);
127662306a36Sopenharmony_ci		if (error)
127762306a36Sopenharmony_ci			goto err_release_cfg;
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	goodix_configure_dev(ts);
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cierr_release_cfg:
128362306a36Sopenharmony_ci	release_firmware(cfg);
128462306a36Sopenharmony_ci	complete_all(&ts->firmware_loading_complete);
128562306a36Sopenharmony_ci}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_cistatic void goodix_disable_regulators(void *arg)
128862306a36Sopenharmony_ci{
128962306a36Sopenharmony_ci	struct goodix_ts_data *ts = arg;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	regulator_disable(ts->vddio);
129262306a36Sopenharmony_ci	regulator_disable(ts->avdd28);
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic int goodix_ts_probe(struct i2c_client *client)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	struct goodix_ts_data *ts;
129862306a36Sopenharmony_ci	const char *cfg_name;
129962306a36Sopenharmony_ci	int error;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
130462306a36Sopenharmony_ci		dev_err(&client->dev, "I2C check functionality failed.\n");
130562306a36Sopenharmony_ci		return -ENXIO;
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
130962306a36Sopenharmony_ci	if (!ts)
131062306a36Sopenharmony_ci		return -ENOMEM;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	ts->client = client;
131362306a36Sopenharmony_ci	i2c_set_clientdata(client, ts);
131462306a36Sopenharmony_ci	init_completion(&ts->firmware_loading_complete);
131562306a36Sopenharmony_ci	ts->contact_size = GOODIX_CONTACT_SIZE;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	error = goodix_get_gpio_config(ts);
131862306a36Sopenharmony_ci	if (error)
131962306a36Sopenharmony_ci		return error;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/* power up the controller */
132262306a36Sopenharmony_ci	error = regulator_enable(ts->avdd28);
132362306a36Sopenharmony_ci	if (error) {
132462306a36Sopenharmony_ci		dev_err(&client->dev,
132562306a36Sopenharmony_ci			"Failed to enable AVDD28 regulator: %d\n",
132662306a36Sopenharmony_ci			error);
132762306a36Sopenharmony_ci		return error;
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	error = regulator_enable(ts->vddio);
133162306a36Sopenharmony_ci	if (error) {
133262306a36Sopenharmony_ci		dev_err(&client->dev,
133362306a36Sopenharmony_ci			"Failed to enable VDDIO regulator: %d\n",
133462306a36Sopenharmony_ci			error);
133562306a36Sopenharmony_ci		regulator_disable(ts->avdd28);
133662306a36Sopenharmony_ci		return error;
133762306a36Sopenharmony_ci	}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	error = devm_add_action_or_reset(&client->dev,
134062306a36Sopenharmony_ci					 goodix_disable_regulators, ts);
134162306a36Sopenharmony_ci	if (error)
134262306a36Sopenharmony_ci		return error;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_cireset:
134562306a36Sopenharmony_ci	if (ts->reset_controller_at_probe) {
134662306a36Sopenharmony_ci		/* reset the controller */
134762306a36Sopenharmony_ci		error = goodix_reset(ts);
134862306a36Sopenharmony_ci		if (error)
134962306a36Sopenharmony_ci			return error;
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	error = goodix_i2c_test(client);
135362306a36Sopenharmony_ci	if (error) {
135462306a36Sopenharmony_ci		if (!ts->reset_controller_at_probe &&
135562306a36Sopenharmony_ci		    ts->irq_pin_access_method != IRQ_PIN_ACCESS_NONE) {
135662306a36Sopenharmony_ci			/* Retry after a controller reset */
135762306a36Sopenharmony_ci			ts->reset_controller_at_probe = true;
135862306a36Sopenharmony_ci			goto reset;
135962306a36Sopenharmony_ci		}
136062306a36Sopenharmony_ci		dev_err(&client->dev, "I2C communication failure: %d\n", error);
136162306a36Sopenharmony_ci		return error;
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	error = goodix_firmware_check(ts);
136562306a36Sopenharmony_ci	if (error)
136662306a36Sopenharmony_ci		return error;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	error = goodix_read_version(ts);
136962306a36Sopenharmony_ci	if (error)
137062306a36Sopenharmony_ci		return error;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ts->chip = goodix_get_chip_data(ts->id);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (ts->load_cfg_from_disk) {
137562306a36Sopenharmony_ci		/* update device config */
137662306a36Sopenharmony_ci		error = device_property_read_string(&client->dev,
137762306a36Sopenharmony_ci						    "goodix,config-name",
137862306a36Sopenharmony_ci						    &cfg_name);
137962306a36Sopenharmony_ci		if (!error)
138062306a36Sopenharmony_ci			snprintf(ts->cfg_name, sizeof(ts->cfg_name),
138162306a36Sopenharmony_ci				 "goodix/%s", cfg_name);
138262306a36Sopenharmony_ci		else
138362306a36Sopenharmony_ci			snprintf(ts->cfg_name, sizeof(ts->cfg_name),
138462306a36Sopenharmony_ci				 "goodix_%s_cfg.bin", ts->id);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci		error = request_firmware_nowait(THIS_MODULE, true, ts->cfg_name,
138762306a36Sopenharmony_ci						&client->dev, GFP_KERNEL, ts,
138862306a36Sopenharmony_ci						goodix_config_cb);
138962306a36Sopenharmony_ci		if (error) {
139062306a36Sopenharmony_ci			dev_err(&client->dev,
139162306a36Sopenharmony_ci				"Failed to invoke firmware loader: %d\n",
139262306a36Sopenharmony_ci				error);
139362306a36Sopenharmony_ci			return error;
139462306a36Sopenharmony_ci		}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci		return 0;
139762306a36Sopenharmony_ci	} else {
139862306a36Sopenharmony_ci		error = goodix_configure_dev(ts);
139962306a36Sopenharmony_ci		if (error)
140062306a36Sopenharmony_ci			return error;
140162306a36Sopenharmony_ci	}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	return 0;
140462306a36Sopenharmony_ci}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_cistatic void goodix_ts_remove(struct i2c_client *client)
140762306a36Sopenharmony_ci{
140862306a36Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	if (ts->load_cfg_from_disk)
141162306a36Sopenharmony_ci		wait_for_completion(&ts->firmware_loading_complete);
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_cistatic int goodix_suspend(struct device *dev)
141562306a36Sopenharmony_ci{
141662306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
141762306a36Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
141862306a36Sopenharmony_ci	int error;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (ts->load_cfg_from_disk)
142162306a36Sopenharmony_ci		wait_for_completion(&ts->firmware_loading_complete);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* We need gpio pins to suspend/resume */
142462306a36Sopenharmony_ci	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
142562306a36Sopenharmony_ci		disable_irq(client->irq);
142662306a36Sopenharmony_ci		return 0;
142762306a36Sopenharmony_ci	}
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/* Free IRQ as IRQ pin is used as output in the suspend sequence */
143062306a36Sopenharmony_ci	goodix_free_irq(ts);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	/* Save reference (calibration) info if necessary */
143362306a36Sopenharmony_ci	goodix_save_bak_ref(ts);
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci	/* Output LOW on the INT pin for 5 ms */
143662306a36Sopenharmony_ci	error = goodix_irq_direction_output(ts, 0);
143762306a36Sopenharmony_ci	if (error) {
143862306a36Sopenharmony_ci		goodix_request_irq(ts);
143962306a36Sopenharmony_ci		return error;
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	usleep_range(5000, 6000);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	error = goodix_i2c_write_u8(ts->client, GOODIX_REG_COMMAND,
144562306a36Sopenharmony_ci				    GOODIX_CMD_SCREEN_OFF);
144662306a36Sopenharmony_ci	if (error) {
144762306a36Sopenharmony_ci		goodix_irq_direction_input(ts);
144862306a36Sopenharmony_ci		goodix_request_irq(ts);
144962306a36Sopenharmony_ci		return -EAGAIN;
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/*
145362306a36Sopenharmony_ci	 * The datasheet specifies that the interval between sending screen-off
145462306a36Sopenharmony_ci	 * command and wake-up should be longer than 58 ms. To avoid waking up
145562306a36Sopenharmony_ci	 * sooner, delay 58ms here.
145662306a36Sopenharmony_ci	 */
145762306a36Sopenharmony_ci	msleep(58);
145862306a36Sopenharmony_ci	return 0;
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_cistatic int goodix_resume(struct device *dev)
146262306a36Sopenharmony_ci{
146362306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
146462306a36Sopenharmony_ci	struct goodix_ts_data *ts = i2c_get_clientdata(client);
146562306a36Sopenharmony_ci	u8 config_ver;
146662306a36Sopenharmony_ci	int error;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
146962306a36Sopenharmony_ci		enable_irq(client->irq);
147062306a36Sopenharmony_ci		return 0;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	/*
147462306a36Sopenharmony_ci	 * Exit sleep mode by outputting HIGH level to INT pin
147562306a36Sopenharmony_ci	 * for 2ms~5ms.
147662306a36Sopenharmony_ci	 */
147762306a36Sopenharmony_ci	error = goodix_irq_direction_output(ts, 1);
147862306a36Sopenharmony_ci	if (error)
147962306a36Sopenharmony_ci		return error;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	usleep_range(2000, 5000);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	error = goodix_int_sync(ts);
148462306a36Sopenharmony_ci	if (error)
148562306a36Sopenharmony_ci		return error;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	error = goodix_i2c_read(ts->client, ts->chip->config_addr,
148862306a36Sopenharmony_ci				&config_ver, 1);
148962306a36Sopenharmony_ci	if (!error && config_ver != ts->config[0])
149062306a36Sopenharmony_ci		dev_info(dev, "Config version mismatch %d != %d, resetting controller\n",
149162306a36Sopenharmony_ci			 config_ver, ts->config[0]);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	if (error != 0 || config_ver != ts->config[0]) {
149462306a36Sopenharmony_ci		error = goodix_reset(ts);
149562306a36Sopenharmony_ci		if (error)
149662306a36Sopenharmony_ci			return error;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		error = goodix_send_cfg(ts, ts->config, ts->chip->config_len);
149962306a36Sopenharmony_ci		if (error)
150062306a36Sopenharmony_ci			return error;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	error = goodix_request_irq(ts);
150462306a36Sopenharmony_ci	if (error)
150562306a36Sopenharmony_ci		return error;
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	return 0;
150862306a36Sopenharmony_ci}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_cistatic const struct i2c_device_id goodix_ts_id[] = {
151362306a36Sopenharmony_ci	{ "GDIX1001:00", 0 },
151462306a36Sopenharmony_ci	{ }
151562306a36Sopenharmony_ci};
151662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, goodix_ts_id);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci#ifdef CONFIG_ACPI
151962306a36Sopenharmony_cistatic const struct acpi_device_id goodix_acpi_match[] = {
152062306a36Sopenharmony_ci	{ "GDIX1001", 0 },
152162306a36Sopenharmony_ci	{ "GDIX1002", 0 },
152262306a36Sopenharmony_ci	{ "GDX9110", 0 },
152362306a36Sopenharmony_ci	{ }
152462306a36Sopenharmony_ci};
152562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
152662306a36Sopenharmony_ci#endif
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci#ifdef CONFIG_OF
152962306a36Sopenharmony_cistatic const struct of_device_id goodix_of_match[] = {
153062306a36Sopenharmony_ci	{ .compatible = "goodix,gt1151" },
153162306a36Sopenharmony_ci	{ .compatible = "goodix,gt1158" },
153262306a36Sopenharmony_ci	{ .compatible = "goodix,gt5663" },
153362306a36Sopenharmony_ci	{ .compatible = "goodix,gt5688" },
153462306a36Sopenharmony_ci	{ .compatible = "goodix,gt911" },
153562306a36Sopenharmony_ci	{ .compatible = "goodix,gt9110" },
153662306a36Sopenharmony_ci	{ .compatible = "goodix,gt912" },
153762306a36Sopenharmony_ci	{ .compatible = "goodix,gt9147" },
153862306a36Sopenharmony_ci	{ .compatible = "goodix,gt917s" },
153962306a36Sopenharmony_ci	{ .compatible = "goodix,gt927" },
154062306a36Sopenharmony_ci	{ .compatible = "goodix,gt9271" },
154162306a36Sopenharmony_ci	{ .compatible = "goodix,gt928" },
154262306a36Sopenharmony_ci	{ .compatible = "goodix,gt9286" },
154362306a36Sopenharmony_ci	{ .compatible = "goodix,gt967" },
154462306a36Sopenharmony_ci	{ }
154562306a36Sopenharmony_ci};
154662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, goodix_of_match);
154762306a36Sopenharmony_ci#endif
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_cistatic struct i2c_driver goodix_ts_driver = {
155062306a36Sopenharmony_ci	.probe = goodix_ts_probe,
155162306a36Sopenharmony_ci	.remove = goodix_ts_remove,
155262306a36Sopenharmony_ci	.id_table = goodix_ts_id,
155362306a36Sopenharmony_ci	.driver = {
155462306a36Sopenharmony_ci		.name = "Goodix-TS",
155562306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(goodix_acpi_match),
155662306a36Sopenharmony_ci		.of_match_table = of_match_ptr(goodix_of_match),
155762306a36Sopenharmony_ci		.pm = pm_sleep_ptr(&goodix_pm_ops),
155862306a36Sopenharmony_ci	},
155962306a36Sopenharmony_ci};
156062306a36Sopenharmony_cimodule_i2c_driver(goodix_ts_driver);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ciMODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
156362306a36Sopenharmony_ciMODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
156462306a36Sopenharmony_ciMODULE_DESCRIPTION("Goodix touchscreen driver");
156562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1566