162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ILITEK Touch IC driver for 23XX, 25XX and Lego series
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2011 ILI Technology Corporation.
662306a36Sopenharmony_ci * Copyright (C) 2020 Luca Hsu <luca_hsu@ilitek.com>
762306a36Sopenharmony_ci * Copyright (C) 2021 Joe Hung <joe_hung@ilitek.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/input.h>
1362306a36Sopenharmony_ci#include <linux/input/mt.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/interrupt.h>
1862306a36Sopenharmony_ci#include <linux/gpio.h>
1962306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
2062306a36Sopenharmony_ci#include <linux/errno.h>
2162306a36Sopenharmony_ci#include <linux/acpi.h>
2262306a36Sopenharmony_ci#include <linux/input/touchscreen.h>
2362306a36Sopenharmony_ci#include <asm/unaligned.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define ILITEK_TS_NAME					"ilitek_ts"
2762306a36Sopenharmony_ci#define BL_V1_8						0x108
2862306a36Sopenharmony_ci#define BL_V1_7						0x107
2962306a36Sopenharmony_ci#define BL_V1_6						0x106
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_TP_RES			0x20
3262306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_SCRN_RES			0x21
3362306a36Sopenharmony_ci#define ILITEK_TP_CMD_SET_IC_SLEEP			0x30
3462306a36Sopenharmony_ci#define ILITEK_TP_CMD_SET_IC_WAKE			0x31
3562306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_FW_VER			0x40
3662306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_PRL_VER			0x42
3762306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_MCU_VER			0x61
3862306a36Sopenharmony_ci#define ILITEK_TP_CMD_GET_IC_MODE			0xC0
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define REPORT_COUNT_ADDRESS				61
4162306a36Sopenharmony_ci#define ILITEK_SUPPORT_MAX_POINT			40
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct ilitek_protocol_info {
4462306a36Sopenharmony_ci	u16 ver;
4562306a36Sopenharmony_ci	u8 ver_major;
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistruct ilitek_ts_data {
4962306a36Sopenharmony_ci	struct i2c_client		*client;
5062306a36Sopenharmony_ci	struct gpio_desc		*reset_gpio;
5162306a36Sopenharmony_ci	struct input_dev		*input_dev;
5262306a36Sopenharmony_ci	struct touchscreen_properties	prop;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	const struct ilitek_protocol_map *ptl_cb_func;
5562306a36Sopenharmony_ci	struct ilitek_protocol_info	ptl;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	char				product_id[30];
5862306a36Sopenharmony_ci	u16				mcu_ver;
5962306a36Sopenharmony_ci	u8				ic_mode;
6062306a36Sopenharmony_ci	u8				firmware_ver[8];
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	s32				reset_time;
6362306a36Sopenharmony_ci	s32				screen_max_x;
6462306a36Sopenharmony_ci	s32				screen_max_y;
6562306a36Sopenharmony_ci	s32				screen_min_x;
6662306a36Sopenharmony_ci	s32				screen_min_y;
6762306a36Sopenharmony_ci	s32				max_tp;
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct ilitek_protocol_map {
7162306a36Sopenharmony_ci	u16 cmd;
7262306a36Sopenharmony_ci	const char *name;
7362306a36Sopenharmony_ci	int (*func)(struct ilitek_ts_data *ts, u16 cmd, u8 *inbuf, u8 *outbuf);
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cienum ilitek_cmds {
7762306a36Sopenharmony_ci	/* common cmds */
7862306a36Sopenharmony_ci	GET_PTL_VER = 0,
7962306a36Sopenharmony_ci	GET_FW_VER,
8062306a36Sopenharmony_ci	GET_SCRN_RES,
8162306a36Sopenharmony_ci	GET_TP_RES,
8262306a36Sopenharmony_ci	GET_IC_MODE,
8362306a36Sopenharmony_ci	GET_MCU_VER,
8462306a36Sopenharmony_ci	SET_IC_SLEEP,
8562306a36Sopenharmony_ci	SET_IC_WAKE,
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/* ALWAYS keep at the end */
8862306a36Sopenharmony_ci	MAX_CMD_CNT
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* ILITEK I2C R/W APIs */
9262306a36Sopenharmony_cistatic int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts,
9362306a36Sopenharmony_ci				     u8 *cmd, int write_len, int delay,
9462306a36Sopenharmony_ci				     u8 *data, int read_len)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	int error;
9762306a36Sopenharmony_ci	struct i2c_client *client = ts->client;
9862306a36Sopenharmony_ci	struct i2c_msg msgs[] = {
9962306a36Sopenharmony_ci		{
10062306a36Sopenharmony_ci			.addr = client->addr,
10162306a36Sopenharmony_ci			.flags = 0,
10262306a36Sopenharmony_ci			.len = write_len,
10362306a36Sopenharmony_ci			.buf = cmd,
10462306a36Sopenharmony_ci		},
10562306a36Sopenharmony_ci		{
10662306a36Sopenharmony_ci			.addr = client->addr,
10762306a36Sopenharmony_ci			.flags = I2C_M_RD,
10862306a36Sopenharmony_ci			.len = read_len,
10962306a36Sopenharmony_ci			.buf = data,
11062306a36Sopenharmony_ci		},
11162306a36Sopenharmony_ci	};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (delay == 0 && write_len > 0 && read_len > 0) {
11462306a36Sopenharmony_ci		error = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
11562306a36Sopenharmony_ci		if (error < 0)
11662306a36Sopenharmony_ci			return error;
11762306a36Sopenharmony_ci	} else {
11862306a36Sopenharmony_ci		if (write_len > 0) {
11962306a36Sopenharmony_ci			error = i2c_transfer(client->adapter, msgs, 1);
12062306a36Sopenharmony_ci			if (error < 0)
12162306a36Sopenharmony_ci				return error;
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci		if (delay > 0)
12462306a36Sopenharmony_ci			mdelay(delay);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		if (read_len > 0) {
12762306a36Sopenharmony_ci			error = i2c_transfer(client->adapter, msgs + 1, 1);
12862306a36Sopenharmony_ci			if (error < 0)
12962306a36Sopenharmony_ci				return error;
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return 0;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* ILITEK ISR APIs */
13762306a36Sopenharmony_cistatic void ilitek_touch_down(struct ilitek_ts_data *ts, unsigned int id,
13862306a36Sopenharmony_ci			      unsigned int x, unsigned int y)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct input_dev *input = ts->input_dev;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	input_mt_slot(input, id);
14362306a36Sopenharmony_ci	input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	touchscreen_report_pos(input, &ts->prop, x, y, true);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	int error = 0;
15162306a36Sopenharmony_ci	u8 buf[512];
15262306a36Sopenharmony_ci	int packet_len = 5;
15362306a36Sopenharmony_ci	int packet_max_point = 10;
15462306a36Sopenharmony_ci	int report_max_point;
15562306a36Sopenharmony_ci	int i, count;
15662306a36Sopenharmony_ci	struct input_dev *input = ts->input_dev;
15762306a36Sopenharmony_ci	struct device *dev = &ts->client->dev;
15862306a36Sopenharmony_ci	unsigned int x, y, status, id;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, NULL, 0, 0, buf, 64);
16162306a36Sopenharmony_ci	if (error) {
16262306a36Sopenharmony_ci		dev_err(dev, "get touch info failed, err:%d\n", error);
16362306a36Sopenharmony_ci		goto err_sync_frame;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	report_max_point = buf[REPORT_COUNT_ADDRESS];
16762306a36Sopenharmony_ci	if (report_max_point > ts->max_tp) {
16862306a36Sopenharmony_ci		dev_err(dev, "FW report max point:%d > panel info. max:%d\n",
16962306a36Sopenharmony_ci			report_max_point, ts->max_tp);
17062306a36Sopenharmony_ci		error = -EINVAL;
17162306a36Sopenharmony_ci		goto err_sync_frame;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	count = DIV_ROUND_UP(report_max_point, packet_max_point);
17562306a36Sopenharmony_ci	for (i = 1; i < count; i++) {
17662306a36Sopenharmony_ci		error = ilitek_i2c_write_and_read(ts, NULL, 0, 0,
17762306a36Sopenharmony_ci						  buf + i * 64, 64);
17862306a36Sopenharmony_ci		if (error) {
17962306a36Sopenharmony_ci			dev_err(dev, "get touch info. failed, cnt:%d, err:%d\n",
18062306a36Sopenharmony_ci				count, error);
18162306a36Sopenharmony_ci			goto err_sync_frame;
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	for (i = 0; i < report_max_point; i++) {
18662306a36Sopenharmony_ci		status = buf[i * packet_len + 1] & 0x40;
18762306a36Sopenharmony_ci		if (!status)
18862306a36Sopenharmony_ci			continue;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci		id = buf[i * packet_len + 1] & 0x3F;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		x = get_unaligned_le16(buf + i * packet_len + 2);
19362306a36Sopenharmony_ci		y = get_unaligned_le16(buf + i * packet_len + 4);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		if (x > ts->screen_max_x || x < ts->screen_min_x ||
19662306a36Sopenharmony_ci		    y > ts->screen_max_y || y < ts->screen_min_y) {
19762306a36Sopenharmony_ci			dev_warn(dev, "invalid position, X[%d,%u,%d], Y[%d,%u,%d]\n",
19862306a36Sopenharmony_ci				 ts->screen_min_x, x, ts->screen_max_x,
19962306a36Sopenharmony_ci				 ts->screen_min_y, y, ts->screen_max_y);
20062306a36Sopenharmony_ci			continue;
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		ilitek_touch_down(ts, id, x, y);
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cierr_sync_frame:
20762306a36Sopenharmony_ci	input_mt_sync_frame(input);
20862306a36Sopenharmony_ci	input_sync(input);
20962306a36Sopenharmony_ci	return error;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/* APIs of cmds for ILITEK Touch IC */
21362306a36Sopenharmony_cistatic int api_protocol_set_cmd(struct ilitek_ts_data *ts,
21462306a36Sopenharmony_ci				u16 idx, u8 *inbuf, u8 *outbuf)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	u16 cmd;
21762306a36Sopenharmony_ci	int error;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (idx >= MAX_CMD_CNT)
22062306a36Sopenharmony_ci		return -EINVAL;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	cmd = ts->ptl_cb_func[idx].cmd;
22362306a36Sopenharmony_ci	error = ts->ptl_cb_func[idx].func(ts, cmd, inbuf, outbuf);
22462306a36Sopenharmony_ci	if (error)
22562306a36Sopenharmony_ci		return error;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int api_protocol_get_ptl_ver(struct ilitek_ts_data *ts,
23162306a36Sopenharmony_ci				    u16 cmd, u8 *inbuf, u8 *outbuf)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	int error;
23462306a36Sopenharmony_ci	u8 buf[64];
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	buf[0] = cmd;
23762306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 3);
23862306a36Sopenharmony_ci	if (error)
23962306a36Sopenharmony_ci		return error;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	ts->ptl.ver = get_unaligned_be16(outbuf);
24262306a36Sopenharmony_ci	ts->ptl.ver_major = outbuf[0];
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int api_protocol_get_mcu_ver(struct ilitek_ts_data *ts,
24862306a36Sopenharmony_ci				    u16 cmd, u8 *inbuf, u8 *outbuf)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int error;
25162306a36Sopenharmony_ci	u8 buf[64];
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	buf[0] = cmd;
25462306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 32);
25562306a36Sopenharmony_ci	if (error)
25662306a36Sopenharmony_ci		return error;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ts->mcu_ver = get_unaligned_le16(outbuf);
25962306a36Sopenharmony_ci	memset(ts->product_id, 0, sizeof(ts->product_id));
26062306a36Sopenharmony_ci	memcpy(ts->product_id, outbuf + 6, 26);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int api_protocol_get_fw_ver(struct ilitek_ts_data *ts,
26662306a36Sopenharmony_ci				   u16 cmd, u8 *inbuf, u8 *outbuf)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	int error;
26962306a36Sopenharmony_ci	u8 buf[64];
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	buf[0] = cmd;
27262306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 8);
27362306a36Sopenharmony_ci	if (error)
27462306a36Sopenharmony_ci		return error;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	memcpy(ts->firmware_ver, outbuf, 8);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int api_protocol_get_scrn_res(struct ilitek_ts_data *ts,
28262306a36Sopenharmony_ci				     u16 cmd, u8 *inbuf, u8 *outbuf)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	int error;
28562306a36Sopenharmony_ci	u8 buf[64];
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	buf[0] = cmd;
28862306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 8);
28962306a36Sopenharmony_ci	if (error)
29062306a36Sopenharmony_ci		return error;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	ts->screen_min_x = get_unaligned_le16(outbuf);
29362306a36Sopenharmony_ci	ts->screen_min_y = get_unaligned_le16(outbuf + 2);
29462306a36Sopenharmony_ci	ts->screen_max_x = get_unaligned_le16(outbuf + 4);
29562306a36Sopenharmony_ci	ts->screen_max_y = get_unaligned_le16(outbuf + 6);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int api_protocol_get_tp_res(struct ilitek_ts_data *ts,
30162306a36Sopenharmony_ci				   u16 cmd, u8 *inbuf, u8 *outbuf)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	int error;
30462306a36Sopenharmony_ci	u8 buf[64];
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	buf[0] = cmd;
30762306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 15);
30862306a36Sopenharmony_ci	if (error)
30962306a36Sopenharmony_ci		return error;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ts->max_tp = outbuf[8];
31262306a36Sopenharmony_ci	if (ts->max_tp > ILITEK_SUPPORT_MAX_POINT) {
31362306a36Sopenharmony_ci		dev_err(&ts->client->dev, "Invalid MAX_TP:%d from FW\n",
31462306a36Sopenharmony_ci			ts->max_tp);
31562306a36Sopenharmony_ci		return -EINVAL;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic int api_protocol_get_ic_mode(struct ilitek_ts_data *ts,
32262306a36Sopenharmony_ci				    u16 cmd, u8 *inbuf, u8 *outbuf)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	int error;
32562306a36Sopenharmony_ci	u8 buf[64];
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	buf[0] = cmd;
32862306a36Sopenharmony_ci	error = ilitek_i2c_write_and_read(ts, buf, 1, 5, outbuf, 2);
32962306a36Sopenharmony_ci	if (error)
33062306a36Sopenharmony_ci		return error;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	ts->ic_mode = outbuf[0];
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int api_protocol_set_ic_sleep(struct ilitek_ts_data *ts,
33762306a36Sopenharmony_ci				     u16 cmd, u8 *inbuf, u8 *outbuf)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	u8 buf[64];
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	buf[0] = cmd;
34262306a36Sopenharmony_ci	return ilitek_i2c_write_and_read(ts, buf, 1, 0, NULL, 0);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int api_protocol_set_ic_wake(struct ilitek_ts_data *ts,
34662306a36Sopenharmony_ci				    u16 cmd, u8 *inbuf, u8 *outbuf)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	u8 buf[64];
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	buf[0] = cmd;
35162306a36Sopenharmony_ci	return ilitek_i2c_write_and_read(ts, buf, 1, 0, NULL, 0);
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic const struct ilitek_protocol_map ptl_func_map[] = {
35562306a36Sopenharmony_ci	/* common cmds */
35662306a36Sopenharmony_ci	[GET_PTL_VER] = {
35762306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_PRL_VER, "GET_PTL_VER",
35862306a36Sopenharmony_ci		api_protocol_get_ptl_ver
35962306a36Sopenharmony_ci	},
36062306a36Sopenharmony_ci	[GET_FW_VER] = {
36162306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_FW_VER, "GET_FW_VER",
36262306a36Sopenharmony_ci		api_protocol_get_fw_ver
36362306a36Sopenharmony_ci	},
36462306a36Sopenharmony_ci	[GET_SCRN_RES] = {
36562306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_SCRN_RES, "GET_SCRN_RES",
36662306a36Sopenharmony_ci		api_protocol_get_scrn_res
36762306a36Sopenharmony_ci	},
36862306a36Sopenharmony_ci	[GET_TP_RES] = {
36962306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_TP_RES, "GET_TP_RES",
37062306a36Sopenharmony_ci		api_protocol_get_tp_res
37162306a36Sopenharmony_ci	},
37262306a36Sopenharmony_ci	[GET_IC_MODE] = {
37362306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_IC_MODE, "GET_IC_MODE",
37462306a36Sopenharmony_ci			   api_protocol_get_ic_mode
37562306a36Sopenharmony_ci	},
37662306a36Sopenharmony_ci	[GET_MCU_VER] = {
37762306a36Sopenharmony_ci		ILITEK_TP_CMD_GET_MCU_VER, "GET_MOD_VER",
37862306a36Sopenharmony_ci			   api_protocol_get_mcu_ver
37962306a36Sopenharmony_ci	},
38062306a36Sopenharmony_ci	[SET_IC_SLEEP] = {
38162306a36Sopenharmony_ci		ILITEK_TP_CMD_SET_IC_SLEEP, "SET_IC_SLEEP",
38262306a36Sopenharmony_ci		api_protocol_set_ic_sleep
38362306a36Sopenharmony_ci	},
38462306a36Sopenharmony_ci	[SET_IC_WAKE] = {
38562306a36Sopenharmony_ci		ILITEK_TP_CMD_SET_IC_WAKE, "SET_IC_WAKE",
38662306a36Sopenharmony_ci		api_protocol_set_ic_wake
38762306a36Sopenharmony_ci	},
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/* Probe APIs */
39162306a36Sopenharmony_cistatic void ilitek_reset(struct ilitek_ts_data *ts, int delay)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	if (ts->reset_gpio) {
39462306a36Sopenharmony_ci		gpiod_set_value(ts->reset_gpio, 1);
39562306a36Sopenharmony_ci		mdelay(10);
39662306a36Sopenharmony_ci		gpiod_set_value(ts->reset_gpio, 0);
39762306a36Sopenharmony_ci		mdelay(delay);
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int ilitek_protocol_init(struct ilitek_ts_data *ts)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	int error;
40462306a36Sopenharmony_ci	u8 outbuf[64];
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	ts->ptl_cb_func = ptl_func_map;
40762306a36Sopenharmony_ci	ts->reset_time = 600;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_PTL_VER, NULL, outbuf);
41062306a36Sopenharmony_ci	if (error)
41162306a36Sopenharmony_ci		return error;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* Protocol v3 is not support currently */
41462306a36Sopenharmony_ci	if (ts->ptl.ver_major == 0x3 ||
41562306a36Sopenharmony_ci	    ts->ptl.ver == BL_V1_6 ||
41662306a36Sopenharmony_ci	    ts->ptl.ver == BL_V1_7)
41762306a36Sopenharmony_ci		return -EINVAL;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return 0;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int ilitek_read_tp_info(struct ilitek_ts_data *ts, bool boot)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	u8 outbuf[256];
42562306a36Sopenharmony_ci	int error;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_PTL_VER, NULL, outbuf);
42862306a36Sopenharmony_ci	if (error)
42962306a36Sopenharmony_ci		return error;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_MCU_VER, NULL, outbuf);
43262306a36Sopenharmony_ci	if (error)
43362306a36Sopenharmony_ci		return error;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_FW_VER, NULL, outbuf);
43662306a36Sopenharmony_ci	if (error)
43762306a36Sopenharmony_ci		return error;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (boot) {
44062306a36Sopenharmony_ci		error = api_protocol_set_cmd(ts, GET_SCRN_RES, NULL,
44162306a36Sopenharmony_ci					     outbuf);
44262306a36Sopenharmony_ci		if (error)
44362306a36Sopenharmony_ci			return error;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_TP_RES, NULL, outbuf);
44762306a36Sopenharmony_ci	if (error)
44862306a36Sopenharmony_ci		return error;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	error = api_protocol_set_cmd(ts, GET_IC_MODE, NULL, outbuf);
45162306a36Sopenharmony_ci	if (error)
45262306a36Sopenharmony_ci		return error;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int ilitek_input_dev_init(struct device *dev, struct ilitek_ts_data *ts)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	int error;
46062306a36Sopenharmony_ci	struct input_dev *input;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	input = devm_input_allocate_device(dev);
46362306a36Sopenharmony_ci	if (!input)
46462306a36Sopenharmony_ci		return -ENOMEM;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	ts->input_dev = input;
46762306a36Sopenharmony_ci	input->name = ILITEK_TS_NAME;
46862306a36Sopenharmony_ci	input->id.bustype = BUS_I2C;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	__set_bit(INPUT_PROP_DIRECT, input->propbit);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	input_set_abs_params(input, ABS_MT_POSITION_X,
47362306a36Sopenharmony_ci			     ts->screen_min_x, ts->screen_max_x, 0, 0);
47462306a36Sopenharmony_ci	input_set_abs_params(input, ABS_MT_POSITION_Y,
47562306a36Sopenharmony_ci			     ts->screen_min_y, ts->screen_max_y, 0, 0);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	touchscreen_parse_properties(input, true, &ts->prop);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	error = input_mt_init_slots(input, ts->max_tp,
48062306a36Sopenharmony_ci				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
48162306a36Sopenharmony_ci	if (error) {
48262306a36Sopenharmony_ci		dev_err(dev, "initialize MT slots failed, err:%d\n", error);
48362306a36Sopenharmony_ci		return error;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	error = input_register_device(input);
48762306a36Sopenharmony_ci	if (error) {
48862306a36Sopenharmony_ci		dev_err(dev, "register input device failed, err:%d\n", error);
48962306a36Sopenharmony_ci		return error;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	return 0;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic irqreturn_t ilitek_i2c_isr(int irq, void *dev_id)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct ilitek_ts_data *ts = dev_id;
49862306a36Sopenharmony_ci	int error;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	error = ilitek_process_and_report_v6(ts);
50162306a36Sopenharmony_ci	if (error < 0) {
50262306a36Sopenharmony_ci		dev_err(&ts->client->dev, "[%s] err:%d\n", __func__, error);
50362306a36Sopenharmony_ci		return IRQ_NONE;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	return IRQ_HANDLED;
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic ssize_t firmware_version_show(struct device *dev,
51062306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
51362306a36Sopenharmony_ci	struct ilitek_ts_data *ts = i2c_get_clientdata(client);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE,
51662306a36Sopenharmony_ci			 "fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n",
51762306a36Sopenharmony_ci			 ts->firmware_ver[0], ts->firmware_ver[1],
51862306a36Sopenharmony_ci			 ts->firmware_ver[2], ts->firmware_ver[3],
51962306a36Sopenharmony_ci			 ts->firmware_ver[4], ts->firmware_ver[5],
52062306a36Sopenharmony_ci			 ts->firmware_ver[6], ts->firmware_ver[7]);
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(firmware_version);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic ssize_t product_id_show(struct device *dev,
52562306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
52862306a36Sopenharmony_ci	struct ilitek_ts_data *ts = i2c_get_clientdata(client);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "product id: [%04X], module: [%s]\n",
53162306a36Sopenharmony_ci			 ts->mcu_ver, ts->product_id);
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(product_id);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic struct attribute *ilitek_sysfs_attrs[] = {
53662306a36Sopenharmony_ci	&dev_attr_firmware_version.attr,
53762306a36Sopenharmony_ci	&dev_attr_product_id.attr,
53862306a36Sopenharmony_ci	NULL
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic struct attribute_group ilitek_attrs_group = {
54262306a36Sopenharmony_ci	.attrs = ilitek_sysfs_attrs,
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic int ilitek_ts_i2c_probe(struct i2c_client *client)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct ilitek_ts_data *ts;
54862306a36Sopenharmony_ci	struct device *dev = &client->dev;
54962306a36Sopenharmony_ci	int error;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
55262306a36Sopenharmony_ci		dev_err(dev, "i2c check functionality failed\n");
55362306a36Sopenharmony_ci		return -ENXIO;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
55762306a36Sopenharmony_ci	if (!ts)
55862306a36Sopenharmony_ci		return -ENOMEM;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ts->client = client;
56162306a36Sopenharmony_ci	i2c_set_clientdata(client, ts);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
56462306a36Sopenharmony_ci	if (IS_ERR(ts->reset_gpio)) {
56562306a36Sopenharmony_ci		error = PTR_ERR(ts->reset_gpio);
56662306a36Sopenharmony_ci		dev_err(dev, "request gpiod failed: %d", error);
56762306a36Sopenharmony_ci		return error;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	ilitek_reset(ts, 1000);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	error = ilitek_protocol_init(ts);
57362306a36Sopenharmony_ci	if (error) {
57462306a36Sopenharmony_ci		dev_err(dev, "protocol init failed: %d", error);
57562306a36Sopenharmony_ci		return error;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	error = ilitek_read_tp_info(ts, true);
57962306a36Sopenharmony_ci	if (error) {
58062306a36Sopenharmony_ci		dev_err(dev, "read tp info failed: %d", error);
58162306a36Sopenharmony_ci		return error;
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	error = ilitek_input_dev_init(dev, ts);
58562306a36Sopenharmony_ci	if (error) {
58662306a36Sopenharmony_ci		dev_err(dev, "input dev init failed: %d", error);
58762306a36Sopenharmony_ci		return error;
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	error = devm_request_threaded_irq(dev, ts->client->irq,
59162306a36Sopenharmony_ci					  NULL, ilitek_i2c_isr, IRQF_ONESHOT,
59262306a36Sopenharmony_ci					  "ilitek_touch_irq", ts);
59362306a36Sopenharmony_ci	if (error) {
59462306a36Sopenharmony_ci		dev_err(dev, "request threaded irq failed: %d\n", error);
59562306a36Sopenharmony_ci		return error;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	error = devm_device_add_group(dev, &ilitek_attrs_group);
59962306a36Sopenharmony_ci	if (error) {
60062306a36Sopenharmony_ci		dev_err(dev, "sysfs create group failed: %d\n", error);
60162306a36Sopenharmony_ci		return error;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int ilitek_suspend(struct device *dev)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
61062306a36Sopenharmony_ci	struct ilitek_ts_data *ts = i2c_get_clientdata(client);
61162306a36Sopenharmony_ci	int error;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	disable_irq(client->irq);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (!device_may_wakeup(dev)) {
61662306a36Sopenharmony_ci		error = api_protocol_set_cmd(ts, SET_IC_SLEEP, NULL, NULL);
61762306a36Sopenharmony_ci		if (error)
61862306a36Sopenharmony_ci			return error;
61962306a36Sopenharmony_ci	}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	return 0;
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic int ilitek_resume(struct device *dev)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
62762306a36Sopenharmony_ci	struct ilitek_ts_data *ts = i2c_get_clientdata(client);
62862306a36Sopenharmony_ci	int error;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!device_may_wakeup(dev)) {
63162306a36Sopenharmony_ci		error = api_protocol_set_cmd(ts, SET_IC_WAKE, NULL, NULL);
63262306a36Sopenharmony_ci		if (error)
63362306a36Sopenharmony_ci			return error;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		ilitek_reset(ts, ts->reset_time);
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	enable_irq(client->irq);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic const struct i2c_device_id ilitek_ts_i2c_id[] = {
64662306a36Sopenharmony_ci	{ ILITEK_TS_NAME, 0 },
64762306a36Sopenharmony_ci	{ },
64862306a36Sopenharmony_ci};
64962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci#ifdef CONFIG_ACPI
65262306a36Sopenharmony_cistatic const struct acpi_device_id ilitekts_acpi_id[] = {
65362306a36Sopenharmony_ci	{ "ILTK0001", 0 },
65462306a36Sopenharmony_ci	{ },
65562306a36Sopenharmony_ci};
65662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, ilitekts_acpi_id);
65762306a36Sopenharmony_ci#endif
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci#ifdef CONFIG_OF
66062306a36Sopenharmony_cistatic const struct of_device_id ilitek_ts_i2c_match[] = {
66162306a36Sopenharmony_ci	{.compatible = "ilitek,ili2130",},
66262306a36Sopenharmony_ci	{.compatible = "ilitek,ili2131",},
66362306a36Sopenharmony_ci	{.compatible = "ilitek,ili2132",},
66462306a36Sopenharmony_ci	{.compatible = "ilitek,ili2316",},
66562306a36Sopenharmony_ci	{.compatible = "ilitek,ili2322",},
66662306a36Sopenharmony_ci	{.compatible = "ilitek,ili2323",},
66762306a36Sopenharmony_ci	{.compatible = "ilitek,ili2326",},
66862306a36Sopenharmony_ci	{.compatible = "ilitek,ili2520",},
66962306a36Sopenharmony_ci	{.compatible = "ilitek,ili2521",},
67062306a36Sopenharmony_ci	{ },
67162306a36Sopenharmony_ci};
67262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ilitek_ts_i2c_match);
67362306a36Sopenharmony_ci#endif
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic struct i2c_driver ilitek_ts_i2c_driver = {
67662306a36Sopenharmony_ci	.driver = {
67762306a36Sopenharmony_ci		.name = ILITEK_TS_NAME,
67862306a36Sopenharmony_ci		.pm = pm_sleep_ptr(&ilitek_pm_ops),
67962306a36Sopenharmony_ci		.of_match_table = of_match_ptr(ilitek_ts_i2c_match),
68062306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(ilitekts_acpi_id),
68162306a36Sopenharmony_ci	},
68262306a36Sopenharmony_ci	.probe = ilitek_ts_i2c_probe,
68362306a36Sopenharmony_ci	.id_table = ilitek_ts_i2c_id,
68462306a36Sopenharmony_ci};
68562306a36Sopenharmony_cimodule_i2c_driver(ilitek_ts_i2c_driver);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ciMODULE_AUTHOR("ILITEK");
68862306a36Sopenharmony_ciMODULE_DESCRIPTION("ILITEK I2C Touchscreen Driver");
68962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
690