1*5b0c03e2SAlistair Francis // SPDX-License-Identifier: GPL-2.0
2*5b0c03e2SAlistair Francis /*
3*5b0c03e2SAlistair Francis  * Parade TrueTouch(TM) Standard Product V5 Module.
4*5b0c03e2SAlistair Francis  *
5*5b0c03e2SAlistair Francis  * Copyright (C) 2015 Parade Technologies
6*5b0c03e2SAlistair Francis  * Copyright (C) 2012-2015 Cypress Semiconductor
7*5b0c03e2SAlistair Francis  * Copyright (C) 2018 Bootlin
8*5b0c03e2SAlistair Francis  *
9*5b0c03e2SAlistair Francis  * Authors: Mylène Josserand <mylene.josserand@bootlin.com>
10*5b0c03e2SAlistair Francis  *                Alistair Francis <alistair@alistair23.me>
11*5b0c03e2SAlistair Francis  */
12*5b0c03e2SAlistair Francis 
13*5b0c03e2SAlistair Francis #include <linux/crc-itu-t.h>
14*5b0c03e2SAlistair Francis #include <linux/delay.h>
15*5b0c03e2SAlistair Francis #include <linux/device.h>
16*5b0c03e2SAlistair Francis #include <linux/gpio/consumer.h>
17*5b0c03e2SAlistair Francis #include <linux/input/mt.h>
18*5b0c03e2SAlistair Francis #include <linux/input/touchscreen.h>
19*5b0c03e2SAlistair Francis #include <linux/interrupt.h>
20*5b0c03e2SAlistair Francis #include <linux/i2c.h>
21*5b0c03e2SAlistair Francis #include <linux/module.h>
22*5b0c03e2SAlistair Francis #include <linux/of_device.h>
23*5b0c03e2SAlistair Francis #include <linux/regmap.h>
24*5b0c03e2SAlistair Francis #include <asm/unaligned.h>
25*5b0c03e2SAlistair Francis 
26*5b0c03e2SAlistair Francis #define CYTTSP5_NAME				"cyttsp5"
27*5b0c03e2SAlistair Francis #define CY_I2C_DATA_SIZE			(2 * 256)
28*5b0c03e2SAlistair Francis #define HID_VERSION				0x0100
29*5b0c03e2SAlistair Francis #define CY_MAX_INPUT				512
30*5b0c03e2SAlistair Francis #define CYTTSP5_PREALLOCATED_CMD_BUFFER		32
31*5b0c03e2SAlistair Francis #define CY_BITS_PER_BTN				1
32*5b0c03e2SAlistair Francis #define CY_NUM_BTN_EVENT_ID			GENMASK(CY_BITS_PER_BTN, 0)
33*5b0c03e2SAlistair Francis 
34*5b0c03e2SAlistair Francis #define MAX_AREA				255
35*5b0c03e2SAlistair Francis #define HID_OUTPUT_BL_SOP			0x1
36*5b0c03e2SAlistair Francis #define HID_OUTPUT_BL_EOP			0x17
37*5b0c03e2SAlistair Francis #define HID_OUTPUT_BL_LAUNCH_APP		0x3B
38*5b0c03e2SAlistair Francis #define HID_OUTPUT_BL_LAUNCH_APP_SIZE		11
39*5b0c03e2SAlistair Francis #define HID_OUTPUT_GET_SYSINFO			0x2
40*5b0c03e2SAlistair Francis #define HID_OUTPUT_GET_SYSINFO_SIZE		5
41*5b0c03e2SAlistair Francis #define HID_OUTPUT_MAX_CMD_SIZE			12
42*5b0c03e2SAlistair Francis 
43*5b0c03e2SAlistair Francis #define HID_DESC_REG				0x1
44*5b0c03e2SAlistair Francis #define HID_INPUT_REG				0x3
45*5b0c03e2SAlistair Francis #define HID_OUTPUT_REG				0x4
46*5b0c03e2SAlistair Francis 
47*5b0c03e2SAlistair Francis #define REPORT_ID_TOUCH				0x1
48*5b0c03e2SAlistair Francis #define REPORT_ID_BTN				0x3
49*5b0c03e2SAlistair Francis #define REPORT_SIZE_5				5
50*5b0c03e2SAlistair Francis #define REPORT_SIZE_8				8
51*5b0c03e2SAlistair Francis #define REPORT_SIZE_16				16
52*5b0c03e2SAlistair Francis 
53*5b0c03e2SAlistair Francis /* Touch reports offsets */
54*5b0c03e2SAlistair Francis /* Header offsets */
55*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_HDR_CONTACTCOUNT	16
56*5b0c03e2SAlistair Francis /* Record offsets */
57*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_CONTACTID		8
58*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_X			16
59*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_Y			32
60*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_P			48
61*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_MAJ			56
62*5b0c03e2SAlistair Francis #define TOUCH_REPORT_DESC_MIN			64
63*5b0c03e2SAlistair Francis 
64*5b0c03e2SAlistair Francis /* HID */
65*5b0c03e2SAlistair Francis #define HID_TOUCH_REPORT_ID			0x1
66*5b0c03e2SAlistair Francis #define HID_BTN_REPORT_ID			0x3
67*5b0c03e2SAlistair Francis #define HID_APP_RESPONSE_REPORT_ID		0x1F
68*5b0c03e2SAlistair Francis #define HID_APP_OUTPUT_REPORT_ID		0x2F
69*5b0c03e2SAlistair Francis #define HID_BL_RESPONSE_REPORT_ID		0x30
70*5b0c03e2SAlistair Francis #define HID_BL_OUTPUT_REPORT_ID			0x40
71*5b0c03e2SAlistair Francis 
72*5b0c03e2SAlistair Francis #define HID_OUTPUT_RESPONSE_REPORT_OFFSET	2
73*5b0c03e2SAlistair Francis #define HID_OUTPUT_RESPONSE_CMD_OFFSET		4
74*5b0c03e2SAlistair Francis #define HID_OUTPUT_RESPONSE_CMD_MASK		GENMASK(6, 0)
75*5b0c03e2SAlistair Francis 
76*5b0c03e2SAlistair Francis #define HID_SYSINFO_SENSING_OFFSET		33
77*5b0c03e2SAlistair Francis #define HID_SYSINFO_BTN_OFFSET			48
78*5b0c03e2SAlistair Francis #define HID_SYSINFO_BTN_MASK			GENMASK(7, 0)
79*5b0c03e2SAlistair Francis #define HID_SYSINFO_MAX_BTN			8
80*5b0c03e2SAlistair Francis 
81*5b0c03e2SAlistair Francis #define CY_HID_OUTPUT_TIMEOUT_MS		200
82*5b0c03e2SAlistair Francis #define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS	3000
83*5b0c03e2SAlistair Francis #define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS	4000
84*5b0c03e2SAlistair Francis 
85*5b0c03e2SAlistair Francis /* maximum number of concurrent tracks */
86*5b0c03e2SAlistair Francis #define TOUCH_REPORT_SIZE			10
87*5b0c03e2SAlistair Francis #define TOUCH_INPUT_HEADER_SIZE			7
88*5b0c03e2SAlistair Francis #define BTN_REPORT_SIZE				9
89*5b0c03e2SAlistair Francis #define BTN_INPUT_HEADER_SIZE			5
90*5b0c03e2SAlistair Francis 
91*5b0c03e2SAlistair Francis #define MAX_CY_TCH_T_IDS			32
92*5b0c03e2SAlistair Francis 
93*5b0c03e2SAlistair Francis /* All usage pages for Touch Report */
94*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_X			0x00010030
95*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_Y			0x00010031
96*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_P			0x000D0030
97*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_CONTACTID		0x000D0051
98*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_CONTACTCOUNT	0x000D0054
99*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_MAJ		0xFF010062
100*5b0c03e2SAlistair Francis #define TOUCH_REPORT_USAGE_PG_MIN		0xFF010063
101*5b0c03e2SAlistair Francis #define TOUCH_COL_USAGE_PG			0x000D0022
102*5b0c03e2SAlistair Francis 
103*5b0c03e2SAlistair Francis /* System Information interface definitions */
104*5b0c03e2SAlistair Francis struct cyttsp5_sensing_conf_data_dev {
105*5b0c03e2SAlistair Francis 	u8 electrodes_x;
106*5b0c03e2SAlistair Francis 	u8 electrodes_y;
107*5b0c03e2SAlistair Francis 	__le16 len_x;
108*5b0c03e2SAlistair Francis 	__le16 len_y;
109*5b0c03e2SAlistair Francis 	__le16 res_x;
110*5b0c03e2SAlistair Francis 	__le16 res_y;
111*5b0c03e2SAlistair Francis 	__le16 max_z;
112*5b0c03e2SAlistair Francis 	u8 origin_x;
113*5b0c03e2SAlistair Francis 	u8 origin_y;
114*5b0c03e2SAlistair Francis 	u8 btn;
115*5b0c03e2SAlistair Francis 	u8 scan_mode;
116*5b0c03e2SAlistair Francis 	u8 max_num_of_tch_per_refresh_cycle;
117*5b0c03e2SAlistair Francis } __packed;
118*5b0c03e2SAlistair Francis 
119*5b0c03e2SAlistair Francis struct cyttsp5_sensing_conf_data {
120*5b0c03e2SAlistair Francis 	u16 res_x;
121*5b0c03e2SAlistair Francis 	u16 res_y;
122*5b0c03e2SAlistair Francis 	u16 max_z;
123*5b0c03e2SAlistair Francis 	u16 len_x;
124*5b0c03e2SAlistair Francis 	u16 len_y;
125*5b0c03e2SAlistair Francis 	u8 origin_x;
126*5b0c03e2SAlistair Francis 	u8 origin_y;
127*5b0c03e2SAlistair Francis 	u8 max_tch;
128*5b0c03e2SAlistair Francis };
129*5b0c03e2SAlistair Francis 
130*5b0c03e2SAlistair Francis enum cyttsp5_tch_abs {	/* for ordering within the extracted touch data array */
131*5b0c03e2SAlistair Francis 	CY_TCH_X,	/* X */
132*5b0c03e2SAlistair Francis 	CY_TCH_Y,	/* Y */
133*5b0c03e2SAlistair Francis 	CY_TCH_P,	/* P (Z) */
134*5b0c03e2SAlistair Francis 	CY_TCH_T,	/* TOUCH ID */
135*5b0c03e2SAlistair Francis 	CY_TCH_MAJ,	/* TOUCH_MAJOR */
136*5b0c03e2SAlistair Francis 	CY_TCH_MIN,	/* TOUCH_MINOR */
137*5b0c03e2SAlistair Francis 	CY_TCH_NUM_ABS
138*5b0c03e2SAlistair Francis };
139*5b0c03e2SAlistair Francis 
140*5b0c03e2SAlistair Francis struct cyttsp5_tch_abs_params {
141*5b0c03e2SAlistair Francis 	size_t ofs;	/* abs byte offset */
142*5b0c03e2SAlistair Francis 	size_t size;	/* size in bits */
143*5b0c03e2SAlistair Francis 	size_t min;	/* min value */
144*5b0c03e2SAlistair Francis 	size_t max;	/* max value */
145*5b0c03e2SAlistair Francis 	size_t bofs;	/* bit offset */
146*5b0c03e2SAlistair Francis };
147*5b0c03e2SAlistair Francis 
148*5b0c03e2SAlistair Francis struct cyttsp5_touch {
149*5b0c03e2SAlistair Francis 	int abs[CY_TCH_NUM_ABS];
150*5b0c03e2SAlistair Francis };
151*5b0c03e2SAlistair Francis 
152*5b0c03e2SAlistair Francis struct cyttsp5_sysinfo {
153*5b0c03e2SAlistair Francis 	struct cyttsp5_sensing_conf_data sensing_conf_data;
154*5b0c03e2SAlistair Francis 	int num_btns;
155*5b0c03e2SAlistair Francis 	struct cyttsp5_tch_abs_params tch_hdr;
156*5b0c03e2SAlistair Francis 	struct cyttsp5_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
157*5b0c03e2SAlistair Francis 	u32 key_code[HID_SYSINFO_MAX_BTN];
158*5b0c03e2SAlistair Francis };
159*5b0c03e2SAlistair Francis 
160*5b0c03e2SAlistair Francis struct cyttsp5_hid_desc {
161*5b0c03e2SAlistair Francis 	__le16 hid_desc_len;
162*5b0c03e2SAlistair Francis 	u8 packet_id;
163*5b0c03e2SAlistair Francis 	u8 reserved_byte;
164*5b0c03e2SAlistair Francis 	__le16 bcd_version;
165*5b0c03e2SAlistair Francis 	__le16 report_desc_len;
166*5b0c03e2SAlistair Francis 	__le16 report_desc_register;
167*5b0c03e2SAlistair Francis 	__le16 input_register;
168*5b0c03e2SAlistair Francis 	__le16 max_input_len;
169*5b0c03e2SAlistair Francis 	__le16 output_register;
170*5b0c03e2SAlistair Francis 	__le16 max_output_len;
171*5b0c03e2SAlistair Francis 	__le16 command_register;
172*5b0c03e2SAlistair Francis 	__le16 data_register;
173*5b0c03e2SAlistair Francis 	__le16 vendor_id;
174*5b0c03e2SAlistair Francis 	__le16 product_id;
175*5b0c03e2SAlistair Francis 	__le16 version_id;
176*5b0c03e2SAlistair Francis 	u8 reserved[4];
177*5b0c03e2SAlistair Francis } __packed;
178*5b0c03e2SAlistair Francis 
179*5b0c03e2SAlistair Francis struct cyttsp5 {
180*5b0c03e2SAlistair Francis 	struct device *dev;
181*5b0c03e2SAlistair Francis 	struct completion cmd_done;
182*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo sysinfo;
183*5b0c03e2SAlistair Francis 	struct cyttsp5_hid_desc hid_desc;
184*5b0c03e2SAlistair Francis 	u8 cmd_buf[CYTTSP5_PREALLOCATED_CMD_BUFFER];
185*5b0c03e2SAlistair Francis 	u8 input_buf[CY_MAX_INPUT];
186*5b0c03e2SAlistair Francis 	u8 response_buf[CY_MAX_INPUT];
187*5b0c03e2SAlistair Francis 	struct gpio_desc *reset_gpio;
188*5b0c03e2SAlistair Francis 	struct input_dev *input;
189*5b0c03e2SAlistair Francis 	char phys[NAME_MAX];
190*5b0c03e2SAlistair Francis 	int num_prv_rec;
191*5b0c03e2SAlistair Francis 	struct regmap *regmap;
192*5b0c03e2SAlistair Francis 	struct touchscreen_properties prop;
193*5b0c03e2SAlistair Francis 	struct regulator *vdd;
194*5b0c03e2SAlistair Francis };
195*5b0c03e2SAlistair Francis 
196*5b0c03e2SAlistair Francis /*
197*5b0c03e2SAlistair Francis  * For what is understood in the datasheet, the register does not
198*5b0c03e2SAlistair Francis  * matter. For consistency, use the Input Register address
199*5b0c03e2SAlistair Francis  * but it does mean anything to the device. The important data
200*5b0c03e2SAlistair Francis  * to send is the I2C address
201*5b0c03e2SAlistair Francis  */
202*5b0c03e2SAlistair Francis static int cyttsp5_read(struct cyttsp5 *ts, u8 *buf, u32 max)
203*5b0c03e2SAlistair Francis {
204*5b0c03e2SAlistair Francis 	int error;
205*5b0c03e2SAlistair Francis 	u32 size;
206*5b0c03e2SAlistair Francis 	u8 temp[2];
207*5b0c03e2SAlistair Francis 
208*5b0c03e2SAlistair Francis 	/* Read the frame to retrieve the size */
209*5b0c03e2SAlistair Francis 	error = regmap_bulk_read(ts->regmap, HID_INPUT_REG, temp, sizeof(temp));
210*5b0c03e2SAlistair Francis 	if (error)
211*5b0c03e2SAlistair Francis 		return error;
212*5b0c03e2SAlistair Francis 
213*5b0c03e2SAlistair Francis 	size = get_unaligned_le16(temp);
214*5b0c03e2SAlistair Francis 	if (!size || size == 2)
215*5b0c03e2SAlistair Francis 		return 0;
216*5b0c03e2SAlistair Francis 
217*5b0c03e2SAlistair Francis 	if (size > max)
218*5b0c03e2SAlistair Francis 		return -EINVAL;
219*5b0c03e2SAlistair Francis 
220*5b0c03e2SAlistair Francis 	/* Get the real value */
221*5b0c03e2SAlistair Francis 	return regmap_bulk_read(ts->regmap, HID_INPUT_REG, buf, size);
222*5b0c03e2SAlistair Francis }
223*5b0c03e2SAlistair Francis 
224*5b0c03e2SAlistair Francis static int cyttsp5_write(struct cyttsp5 *ts, unsigned int reg, u8 *data,
225*5b0c03e2SAlistair Francis 			 size_t size)
226*5b0c03e2SAlistair Francis {
227*5b0c03e2SAlistair Francis 	u8 cmd[HID_OUTPUT_MAX_CMD_SIZE];
228*5b0c03e2SAlistair Francis 
229*5b0c03e2SAlistair Francis 	if (size + 1 > HID_OUTPUT_MAX_CMD_SIZE)
230*5b0c03e2SAlistair Francis 		return -E2BIG;
231*5b0c03e2SAlistair Francis 
232*5b0c03e2SAlistair Francis 	/* High bytes of register address needed as first byte of cmd */
233*5b0c03e2SAlistair Francis 	cmd[0] = (reg >> 8) & 0xFF;
234*5b0c03e2SAlistair Francis 
235*5b0c03e2SAlistair Francis 	/* Copy the rest of the data */
236*5b0c03e2SAlistair Francis 	if (data)
237*5b0c03e2SAlistair Francis 		memcpy(&cmd[1], data, size);
238*5b0c03e2SAlistair Francis 
239*5b0c03e2SAlistair Francis 	/*
240*5b0c03e2SAlistair Francis 	 * The hardware wants to receive a frame with the address register
241*5b0c03e2SAlistair Francis 	 * contained in the first two bytes. As the regmap_write function
242*5b0c03e2SAlistair Francis 	 * add the register adresse in the frame, we use the low byte as
243*5b0c03e2SAlistair Francis 	 * first frame byte for the address register and the first
244*5b0c03e2SAlistair Francis 	 * data byte is the high register + left of the cmd to send
245*5b0c03e2SAlistair Francis 	 */
246*5b0c03e2SAlistair Francis 	return regmap_bulk_write(ts->regmap, reg & 0xFF, cmd, size + 1);
247*5b0c03e2SAlistair Francis }
248*5b0c03e2SAlistair Francis 
249*5b0c03e2SAlistair Francis static void cyttsp5_get_touch_axis(int *axis, int size, int max, u8 *xy_data,
250*5b0c03e2SAlistair Francis 				   int bofs)
251*5b0c03e2SAlistair Francis {
252*5b0c03e2SAlistair Francis 	int nbyte;
253*5b0c03e2SAlistair Francis 
254*5b0c03e2SAlistair Francis 	for (nbyte = 0, *axis = 0; nbyte < size; nbyte++)
255*5b0c03e2SAlistair Francis 		*axis += ((xy_data[nbyte] >> bofs) << (nbyte * 8));
256*5b0c03e2SAlistair Francis 
257*5b0c03e2SAlistair Francis 	*axis &= max - 1;
258*5b0c03e2SAlistair Francis }
259*5b0c03e2SAlistair Francis 
260*5b0c03e2SAlistair Francis static void cyttsp5_get_touch_record(struct cyttsp5 *ts,
261*5b0c03e2SAlistair Francis 				     struct cyttsp5_touch *touch, u8 *xy_data)
262*5b0c03e2SAlistair Francis {
263*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
264*5b0c03e2SAlistair Francis 	enum cyttsp5_tch_abs abs;
265*5b0c03e2SAlistair Francis 
266*5b0c03e2SAlistair Francis 	for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++)
267*5b0c03e2SAlistair Francis 		cyttsp5_get_touch_axis(&touch->abs[abs],
268*5b0c03e2SAlistair Francis 				       si->tch_abs[abs].size,
269*5b0c03e2SAlistair Francis 				       si->tch_abs[abs].max,
270*5b0c03e2SAlistair Francis 				       xy_data + si->tch_abs[abs].ofs,
271*5b0c03e2SAlistair Francis 				       si->tch_abs[abs].bofs);
272*5b0c03e2SAlistair Francis }
273*5b0c03e2SAlistair Francis 
274*5b0c03e2SAlistair Francis static void cyttsp5_get_mt_touches(struct cyttsp5 *ts,
275*5b0c03e2SAlistair Francis 				   struct cyttsp5_touch *tch, int num_cur_tch)
276*5b0c03e2SAlistair Francis {
277*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
278*5b0c03e2SAlistair Francis 	int i, t = 0, offset = 0;
279*5b0c03e2SAlistair Francis 	DECLARE_BITMAP(ids, MAX_CY_TCH_T_IDS);
280*5b0c03e2SAlistair Francis 	u8 *tch_addr;
281*5b0c03e2SAlistair Francis 	int tmp;
282*5b0c03e2SAlistair Francis 
283*5b0c03e2SAlistair Francis 	bitmap_zero(ids, MAX_CY_TCH_T_IDS);
284*5b0c03e2SAlistair Francis 	memset(tch->abs, 0, sizeof(tch->abs));
285*5b0c03e2SAlistair Francis 
286*5b0c03e2SAlistair Francis 	switch (ts->input_buf[2]) {
287*5b0c03e2SAlistair Francis 	case HID_TOUCH_REPORT_ID:
288*5b0c03e2SAlistair Francis 		offset = TOUCH_INPUT_HEADER_SIZE;
289*5b0c03e2SAlistair Francis 		break;
290*5b0c03e2SAlistair Francis 	case HID_BTN_REPORT_ID:
291*5b0c03e2SAlistair Francis 		offset = BTN_INPUT_HEADER_SIZE;
292*5b0c03e2SAlistair Francis 		break;
293*5b0c03e2SAlistair Francis 	}
294*5b0c03e2SAlistair Francis 
295*5b0c03e2SAlistair Francis 	for (i = 0; i < num_cur_tch; i++) {
296*5b0c03e2SAlistair Francis 		tch_addr = ts->input_buf + offset + (i * TOUCH_REPORT_SIZE);
297*5b0c03e2SAlistair Francis 		cyttsp5_get_touch_record(ts, tch, tch_addr);
298*5b0c03e2SAlistair Francis 
299*5b0c03e2SAlistair Francis 		/* Convert MAJOR/MINOR from mm to resolution */
300*5b0c03e2SAlistair Francis 		tmp = tch->abs[CY_TCH_MAJ] * 100 * si->sensing_conf_data.res_x;
301*5b0c03e2SAlistair Francis 		tch->abs[CY_TCH_MAJ] = tmp / si->sensing_conf_data.len_x;
302*5b0c03e2SAlistair Francis 		tmp = tch->abs[CY_TCH_MIN] * 100 * si->sensing_conf_data.res_x;
303*5b0c03e2SAlistair Francis 		tch->abs[CY_TCH_MIN] = tmp / si->sensing_conf_data.len_x;
304*5b0c03e2SAlistair Francis 
305*5b0c03e2SAlistair Francis 		t = tch->abs[CY_TCH_T];
306*5b0c03e2SAlistair Francis 		input_mt_slot(ts->input, t);
307*5b0c03e2SAlistair Francis 		input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
308*5b0c03e2SAlistair Francis 		__set_bit(t, ids);
309*5b0c03e2SAlistair Francis 
310*5b0c03e2SAlistair Francis 		/* position and pressure fields */
311*5b0c03e2SAlistair Francis 		touchscreen_report_pos(ts->input, &ts->prop,
312*5b0c03e2SAlistair Francis 				       tch->abs[CY_TCH_X], tch->abs[CY_TCH_Y],
313*5b0c03e2SAlistair Francis 				       true);
314*5b0c03e2SAlistair Francis 		input_report_abs(ts->input, ABS_MT_PRESSURE,
315*5b0c03e2SAlistair Francis 				 tch->abs[CY_TCH_P]);
316*5b0c03e2SAlistair Francis 
317*5b0c03e2SAlistair Francis 		/* Get the extended touch fields */
318*5b0c03e2SAlistair Francis 		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
319*5b0c03e2SAlistair Francis 				 tch->abs[CY_TCH_MAJ]);
320*5b0c03e2SAlistair Francis 		input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
321*5b0c03e2SAlistair Francis 				 tch->abs[CY_TCH_MIN]);
322*5b0c03e2SAlistair Francis 	}
323*5b0c03e2SAlistair Francis 
324*5b0c03e2SAlistair Francis 	ts->num_prv_rec = num_cur_tch;
325*5b0c03e2SAlistair Francis }
326*5b0c03e2SAlistair Francis 
327*5b0c03e2SAlistair Francis static int cyttsp5_mt_attention(struct device *dev)
328*5b0c03e2SAlistair Francis {
329*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = dev_get_drvdata(dev);
330*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
331*5b0c03e2SAlistair Francis 	int max_tch = si->sensing_conf_data.max_tch;
332*5b0c03e2SAlistair Francis 	struct cyttsp5_touch tch;
333*5b0c03e2SAlistair Francis 	int num_cur_tch;
334*5b0c03e2SAlistair Francis 
335*5b0c03e2SAlistair Francis 	cyttsp5_get_touch_axis(&num_cur_tch, si->tch_hdr.size,
336*5b0c03e2SAlistair Francis 			       si->tch_hdr.max,
337*5b0c03e2SAlistair Francis 			       ts->input_buf + 3 + si->tch_hdr.ofs,
338*5b0c03e2SAlistair Francis 			       si->tch_hdr.bofs);
339*5b0c03e2SAlistair Francis 
340*5b0c03e2SAlistair Francis 	if (num_cur_tch > max_tch) {
341*5b0c03e2SAlistair Francis 		dev_err(dev, "Num touch err detected (n=%d)\n", num_cur_tch);
342*5b0c03e2SAlistair Francis 		num_cur_tch = max_tch;
343*5b0c03e2SAlistair Francis 	}
344*5b0c03e2SAlistair Francis 
345*5b0c03e2SAlistair Francis 	if (num_cur_tch == 0 && ts->num_prv_rec == 0)
346*5b0c03e2SAlistair Francis 		return 0;
347*5b0c03e2SAlistair Francis 
348*5b0c03e2SAlistair Francis 	/* extract xy_data for all currently reported touches */
349*5b0c03e2SAlistair Francis 	if (num_cur_tch)
350*5b0c03e2SAlistair Francis 		cyttsp5_get_mt_touches(ts, &tch, num_cur_tch);
351*5b0c03e2SAlistair Francis 
352*5b0c03e2SAlistair Francis 	input_mt_sync_frame(ts->input);
353*5b0c03e2SAlistair Francis 	input_sync(ts->input);
354*5b0c03e2SAlistair Francis 
355*5b0c03e2SAlistair Francis 	return 0;
356*5b0c03e2SAlistair Francis }
357*5b0c03e2SAlistair Francis 
358*5b0c03e2SAlistair Francis static int cyttsp5_setup_input_device(struct device *dev)
359*5b0c03e2SAlistair Francis {
360*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = dev_get_drvdata(dev);
361*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
362*5b0c03e2SAlistair Francis 	int max_x, max_y, max_p;
363*5b0c03e2SAlistair Francis 	int max_x_tmp, max_y_tmp;
364*5b0c03e2SAlistair Francis 	int error;
365*5b0c03e2SAlistair Francis 
366*5b0c03e2SAlistair Francis 	max_x_tmp = si->sensing_conf_data.res_x;
367*5b0c03e2SAlistair Francis 	max_y_tmp = si->sensing_conf_data.res_y;
368*5b0c03e2SAlistair Francis 	max_x = max_x_tmp - 1;
369*5b0c03e2SAlistair Francis 	max_y = max_y_tmp - 1;
370*5b0c03e2SAlistair Francis 	max_p = si->sensing_conf_data.max_z;
371*5b0c03e2SAlistair Francis 
372*5b0c03e2SAlistair Francis 	input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
373*5b0c03e2SAlistair Francis 	input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
374*5b0c03e2SAlistair Francis 	input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, max_p, 0, 0);
375*5b0c03e2SAlistair Francis 
376*5b0c03e2SAlistair Francis 	input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, MAX_AREA, 0, 0);
377*5b0c03e2SAlistair Francis 	input_set_abs_params(ts->input, ABS_MT_TOUCH_MINOR, 0, MAX_AREA, 0, 0);
378*5b0c03e2SAlistair Francis 
379*5b0c03e2SAlistair Francis 	error = input_mt_init_slots(ts->input, si->tch_abs[CY_TCH_T].max,
380*5b0c03e2SAlistair Francis 				    INPUT_MT_DROP_UNUSED | INPUT_MT_DIRECT);
381*5b0c03e2SAlistair Francis 	if (error)
382*5b0c03e2SAlistair Francis 		return error;
383*5b0c03e2SAlistair Francis 
384*5b0c03e2SAlistair Francis 	error = input_register_device(ts->input);
385*5b0c03e2SAlistair Francis 	if (error) {
386*5b0c03e2SAlistair Francis 		dev_err(dev, "failed to register input device: %d\n", error);
387*5b0c03e2SAlistair Francis 		return error;
388*5b0c03e2SAlistair Francis 	}
389*5b0c03e2SAlistair Francis 
390*5b0c03e2SAlistair Francis 	return error;
391*5b0c03e2SAlistair Francis }
392*5b0c03e2SAlistair Francis 
393*5b0c03e2SAlistair Francis static int cyttsp5_parse_dt_key_code(struct device *dev)
394*5b0c03e2SAlistair Francis {
395*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = dev_get_drvdata(dev);
396*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
397*5b0c03e2SAlistair Francis 
398*5b0c03e2SAlistair Francis 	if (!si->num_btns)
399*5b0c03e2SAlistair Francis 		return 0;
400*5b0c03e2SAlistair Francis 
401*5b0c03e2SAlistair Francis 	/* Initialize the button to RESERVED */
402*5b0c03e2SAlistair Francis 	memset32(si->key_code, KEY_RESERVED,  si->num_btns);
403*5b0c03e2SAlistair Francis 
404*5b0c03e2SAlistair Francis 	return device_property_read_u32_array(dev, "linux,keycodes",
405*5b0c03e2SAlistair Francis 					      si->key_code, si->num_btns);
406*5b0c03e2SAlistair Francis }
407*5b0c03e2SAlistair Francis 
408*5b0c03e2SAlistair Francis static int cyttsp5_btn_attention(struct device *dev)
409*5b0c03e2SAlistair Francis {
410*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = dev_get_drvdata(dev);
411*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
412*5b0c03e2SAlistair Francis 	int cur_btn, offset = 0;
413*5b0c03e2SAlistair Francis 	int cur_btn_state;
414*5b0c03e2SAlistair Francis 
415*5b0c03e2SAlistair Francis 	switch (ts->input_buf[2]) {
416*5b0c03e2SAlistair Francis 	case HID_TOUCH_REPORT_ID:
417*5b0c03e2SAlistair Francis 		offset = TOUCH_INPUT_HEADER_SIZE;
418*5b0c03e2SAlistair Francis 		break;
419*5b0c03e2SAlistair Francis 	case HID_BTN_REPORT_ID:
420*5b0c03e2SAlistair Francis 		offset = BTN_INPUT_HEADER_SIZE;
421*5b0c03e2SAlistair Francis 		break;
422*5b0c03e2SAlistair Francis 	}
423*5b0c03e2SAlistair Francis 
424*5b0c03e2SAlistair Francis 	if (ts->input_buf[2] != HID_BTN_REPORT_ID)
425*5b0c03e2SAlistair Francis 		return 0;
426*5b0c03e2SAlistair Francis 
427*5b0c03e2SAlistair Francis 	/* extract button press/release touch information */
428*5b0c03e2SAlistair Francis 	for (cur_btn = 0; cur_btn < si->num_btns; cur_btn++) {
429*5b0c03e2SAlistair Francis 		/* Get current button state */
430*5b0c03e2SAlistair Francis 		cur_btn_state = (ts->input_buf[offset] >> (cur_btn * CY_BITS_PER_BTN))
431*5b0c03e2SAlistair Francis 				& CY_NUM_BTN_EVENT_ID;
432*5b0c03e2SAlistair Francis 
433*5b0c03e2SAlistair Francis 		input_report_key(ts->input, si->key_code[cur_btn],
434*5b0c03e2SAlistair Francis 				 cur_btn_state);
435*5b0c03e2SAlistair Francis 		input_sync(ts->input);
436*5b0c03e2SAlistair Francis 	}
437*5b0c03e2SAlistair Francis 
438*5b0c03e2SAlistair Francis 	return 0;
439*5b0c03e2SAlistair Francis }
440*5b0c03e2SAlistair Francis 
441*5b0c03e2SAlistair Francis static int cyttsp5_validate_cmd_response(struct cyttsp5 *ts, u8 code)
442*5b0c03e2SAlistair Francis {
443*5b0c03e2SAlistair Francis 	u16 size, crc;
444*5b0c03e2SAlistair Francis 	u8 status, report_id;
445*5b0c03e2SAlistair Francis 	int command_code;
446*5b0c03e2SAlistair Francis 
447*5b0c03e2SAlistair Francis 	size = get_unaligned_le16(&ts->response_buf[0]);
448*5b0c03e2SAlistair Francis 	if (!size)
449*5b0c03e2SAlistair Francis 		return 0;
450*5b0c03e2SAlistair Francis 
451*5b0c03e2SAlistair Francis 	report_id = ts->response_buf[HID_OUTPUT_RESPONSE_REPORT_OFFSET];
452*5b0c03e2SAlistair Francis 
453*5b0c03e2SAlistair Francis 	switch (report_id) {
454*5b0c03e2SAlistair Francis 	case HID_BL_RESPONSE_REPORT_ID:
455*5b0c03e2SAlistair Francis 		if (ts->response_buf[4] != HID_OUTPUT_BL_SOP) {
456*5b0c03e2SAlistair Francis 			dev_err(ts->dev, "HID output response, wrong SOP\n");
457*5b0c03e2SAlistair Francis 			return -EPROTO;
458*5b0c03e2SAlistair Francis 		}
459*5b0c03e2SAlistair Francis 
460*5b0c03e2SAlistair Francis 		if (ts->response_buf[size - 1] != HID_OUTPUT_BL_EOP) {
461*5b0c03e2SAlistair Francis 			dev_err(ts->dev, "HID output response, wrong EOP\n");
462*5b0c03e2SAlistair Francis 			return -EPROTO;
463*5b0c03e2SAlistair Francis 		}
464*5b0c03e2SAlistair Francis 
465*5b0c03e2SAlistair Francis 		crc = crc_itu_t(0xFFFF, &ts->response_buf[4], size - 7);
466*5b0c03e2SAlistair Francis 		if (get_unaligned_le16(&ts->response_buf[size - 3]) != crc) {
467*5b0c03e2SAlistair Francis 			dev_err(ts->dev,
468*5b0c03e2SAlistair Francis 				"HID output response, wrong CRC 0x%X\n",
469*5b0c03e2SAlistair Francis 				crc);
470*5b0c03e2SAlistair Francis 			return -EPROTO;
471*5b0c03e2SAlistair Francis 		}
472*5b0c03e2SAlistair Francis 
473*5b0c03e2SAlistair Francis 		status = ts->response_buf[5];
474*5b0c03e2SAlistair Francis 		if (status) {
475*5b0c03e2SAlistair Francis 			dev_err(ts->dev, "HID output response, ERROR:%d\n",
476*5b0c03e2SAlistair Francis 				status);
477*5b0c03e2SAlistair Francis 			return -EPROTO;
478*5b0c03e2SAlistair Francis 		}
479*5b0c03e2SAlistair Francis 		break;
480*5b0c03e2SAlistair Francis 
481*5b0c03e2SAlistair Francis 	case HID_APP_RESPONSE_REPORT_ID:
482*5b0c03e2SAlistair Francis 		command_code = ts->response_buf[HID_OUTPUT_RESPONSE_CMD_OFFSET]
483*5b0c03e2SAlistair Francis 			& HID_OUTPUT_RESPONSE_CMD_MASK;
484*5b0c03e2SAlistair Francis 		if (command_code != code) {
485*5b0c03e2SAlistair Francis 			dev_err(ts->dev,
486*5b0c03e2SAlistair Francis 				"HID output response, wrong command_code:%X\n",
487*5b0c03e2SAlistair Francis 				command_code);
488*5b0c03e2SAlistair Francis 			return -EPROTO;
489*5b0c03e2SAlistair Francis 		}
490*5b0c03e2SAlistair Francis 		break;
491*5b0c03e2SAlistair Francis 	}
492*5b0c03e2SAlistair Francis 
493*5b0c03e2SAlistair Francis 	return 0;
494*5b0c03e2SAlistair Francis }
495*5b0c03e2SAlistair Francis 
496*5b0c03e2SAlistair Francis static void cyttsp5_si_get_btn_data(struct cyttsp5 *ts)
497*5b0c03e2SAlistair Francis {
498*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
499*5b0c03e2SAlistair Francis 	unsigned int btns = ts->response_buf[HID_SYSINFO_BTN_OFFSET] &
500*5b0c03e2SAlistair Francis 				HID_SYSINFO_BTN_MASK;
501*5b0c03e2SAlistair Francis 
502*5b0c03e2SAlistair Francis 	si->num_btns = hweight8(btns);
503*5b0c03e2SAlistair Francis }
504*5b0c03e2SAlistair Francis 
505*5b0c03e2SAlistair Francis static int cyttsp5_get_sysinfo_regs(struct cyttsp5 *ts)
506*5b0c03e2SAlistair Francis {
507*5b0c03e2SAlistair Francis 	struct cyttsp5_sensing_conf_data *scd = &ts->sysinfo.sensing_conf_data;
508*5b0c03e2SAlistair Francis 	struct cyttsp5_sensing_conf_data_dev *scd_dev =
509*5b0c03e2SAlistair Francis 		(struct cyttsp5_sensing_conf_data_dev *)
510*5b0c03e2SAlistair Francis 		&ts->response_buf[HID_SYSINFO_SENSING_OFFSET];
511*5b0c03e2SAlistair Francis 
512*5b0c03e2SAlistair Francis 	cyttsp5_si_get_btn_data(ts);
513*5b0c03e2SAlistair Francis 
514*5b0c03e2SAlistair Francis 	scd->max_tch = scd_dev->max_num_of_tch_per_refresh_cycle;
515*5b0c03e2SAlistair Francis 	scd->res_x = get_unaligned_le16(&scd_dev->res_x);
516*5b0c03e2SAlistair Francis 	scd->res_y = get_unaligned_le16(&scd_dev->res_y);
517*5b0c03e2SAlistair Francis 	scd->max_z = get_unaligned_le16(&scd_dev->max_z);
518*5b0c03e2SAlistair Francis 	scd->len_x = get_unaligned_le16(&scd_dev->len_x);
519*5b0c03e2SAlistair Francis 	scd->len_y = get_unaligned_le16(&scd_dev->len_y);
520*5b0c03e2SAlistair Francis 
521*5b0c03e2SAlistair Francis 	return 0;
522*5b0c03e2SAlistair Francis }
523*5b0c03e2SAlistair Francis 
524*5b0c03e2SAlistair Francis static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts)
525*5b0c03e2SAlistair Francis {
526*5b0c03e2SAlistair Francis 	int rc;
527*5b0c03e2SAlistair Francis 	u8 cmd[HID_OUTPUT_GET_SYSINFO_SIZE];
528*5b0c03e2SAlistair Francis 
529*5b0c03e2SAlistair Francis 	/* HI bytes of Output register address */
530*5b0c03e2SAlistair Francis 	put_unaligned_le16(HID_OUTPUT_GET_SYSINFO_SIZE, cmd);
531*5b0c03e2SAlistair Francis 	cmd[2] = HID_APP_OUTPUT_REPORT_ID;
532*5b0c03e2SAlistair Francis 	cmd[3] = 0x0; /* Reserved */
533*5b0c03e2SAlistair Francis 	cmd[4] = HID_OUTPUT_GET_SYSINFO;
534*5b0c03e2SAlistair Francis 
535*5b0c03e2SAlistair Francis 	rc = cyttsp5_write(ts, HID_OUTPUT_REG, cmd,
536*5b0c03e2SAlistair Francis 			   HID_OUTPUT_GET_SYSINFO_SIZE);
537*5b0c03e2SAlistair Francis 	if (rc) {
538*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Failed to write command %d", rc);
539*5b0c03e2SAlistair Francis 		return rc;
540*5b0c03e2SAlistair Francis 	}
541*5b0c03e2SAlistair Francis 
542*5b0c03e2SAlistair Francis 	rc = wait_for_completion_interruptible_timeout(&ts->cmd_done,
543*5b0c03e2SAlistair Francis 						msecs_to_jiffies(CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS));
544*5b0c03e2SAlistair Francis 	if (rc <= 0) {
545*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "HID output cmd execution timed out\n");
546*5b0c03e2SAlistair Francis 		rc = -ETIMEDOUT;
547*5b0c03e2SAlistair Francis 		return rc;
548*5b0c03e2SAlistair Francis 	}
549*5b0c03e2SAlistair Francis 
550*5b0c03e2SAlistair Francis 	rc = cyttsp5_validate_cmd_response(ts, HID_OUTPUT_GET_SYSINFO);
551*5b0c03e2SAlistair Francis 	if (rc) {
552*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Validation of the response failed\n");
553*5b0c03e2SAlistair Francis 		return rc;
554*5b0c03e2SAlistair Francis 	}
555*5b0c03e2SAlistair Francis 
556*5b0c03e2SAlistair Francis 	return cyttsp5_get_sysinfo_regs(ts);
557*5b0c03e2SAlistair Francis }
558*5b0c03e2SAlistair Francis 
559*5b0c03e2SAlistair Francis static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts)
560*5b0c03e2SAlistair Francis {
561*5b0c03e2SAlistair Francis 	int rc;
562*5b0c03e2SAlistair Francis 	u8 cmd[HID_OUTPUT_BL_LAUNCH_APP];
563*5b0c03e2SAlistair Francis 	u16 crc;
564*5b0c03e2SAlistair Francis 
565*5b0c03e2SAlistair Francis 	put_unaligned_le16(HID_OUTPUT_BL_LAUNCH_APP_SIZE, cmd);
566*5b0c03e2SAlistair Francis 	cmd[2] = HID_BL_OUTPUT_REPORT_ID;
567*5b0c03e2SAlistair Francis 	cmd[3] = 0x0; /* Reserved */
568*5b0c03e2SAlistair Francis 	cmd[4] = HID_OUTPUT_BL_SOP;
569*5b0c03e2SAlistair Francis 	cmd[5] = HID_OUTPUT_BL_LAUNCH_APP;
570*5b0c03e2SAlistair Francis 	put_unaligned_le16(0x00, &cmd[6]);
571*5b0c03e2SAlistair Francis 	crc = crc_itu_t(0xFFFF, &cmd[4], 4);
572*5b0c03e2SAlistair Francis 	put_unaligned_le16(crc, &cmd[8]);
573*5b0c03e2SAlistair Francis 	cmd[10] = HID_OUTPUT_BL_EOP;
574*5b0c03e2SAlistair Francis 
575*5b0c03e2SAlistair Francis 	rc = cyttsp5_write(ts, HID_OUTPUT_REG, cmd,
576*5b0c03e2SAlistair Francis 			   HID_OUTPUT_BL_LAUNCH_APP_SIZE);
577*5b0c03e2SAlistair Francis 	if (rc) {
578*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Failed to write command %d", rc);
579*5b0c03e2SAlistair Francis 		return rc;
580*5b0c03e2SAlistair Francis 	}
581*5b0c03e2SAlistair Francis 
582*5b0c03e2SAlistair Francis 	rc = wait_for_completion_interruptible_timeout(&ts->cmd_done,
583*5b0c03e2SAlistair Francis 				msecs_to_jiffies(CY_HID_OUTPUT_TIMEOUT_MS));
584*5b0c03e2SAlistair Francis 	if (rc <= 0) {
585*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "HID output cmd execution timed out\n");
586*5b0c03e2SAlistair Francis 		rc = -ETIMEDOUT;
587*5b0c03e2SAlistair Francis 		return rc;
588*5b0c03e2SAlistair Francis 	}
589*5b0c03e2SAlistair Francis 
590*5b0c03e2SAlistair Francis 	rc = cyttsp5_validate_cmd_response(ts, HID_OUTPUT_BL_LAUNCH_APP);
591*5b0c03e2SAlistair Francis 	if (rc) {
592*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Validation of the response failed\n");
593*5b0c03e2SAlistair Francis 		return rc;
594*5b0c03e2SAlistair Francis 	}
595*5b0c03e2SAlistair Francis 
596*5b0c03e2SAlistair Francis 	return 0;
597*5b0c03e2SAlistair Francis }
598*5b0c03e2SAlistair Francis 
599*5b0c03e2SAlistair Francis static int cyttsp5_get_hid_descriptor(struct cyttsp5 *ts,
600*5b0c03e2SAlistair Francis 				      struct cyttsp5_hid_desc *desc)
601*5b0c03e2SAlistair Francis {
602*5b0c03e2SAlistair Francis 	struct device *dev = ts->dev;
603*5b0c03e2SAlistair Francis 	__le16 hid_desc_register = cpu_to_le16(HID_DESC_REG);
604*5b0c03e2SAlistair Francis 	int rc;
605*5b0c03e2SAlistair Francis 	u8 cmd[2];
606*5b0c03e2SAlistair Francis 
607*5b0c03e2SAlistair Francis 	/* Set HID descriptor register */
608*5b0c03e2SAlistair Francis 	memcpy(cmd, &hid_desc_register, sizeof(hid_desc_register));
609*5b0c03e2SAlistair Francis 
610*5b0c03e2SAlistair Francis 	rc = cyttsp5_write(ts, HID_DESC_REG, NULL, 0);
611*5b0c03e2SAlistair Francis 	if (rc) {
612*5b0c03e2SAlistair Francis 		dev_err(dev, "Failed to get HID descriptor, rc=%d\n", rc);
613*5b0c03e2SAlistair Francis 		return rc;
614*5b0c03e2SAlistair Francis 	}
615*5b0c03e2SAlistair Francis 
616*5b0c03e2SAlistair Francis 	rc = wait_for_completion_interruptible_timeout(&ts->cmd_done,
617*5b0c03e2SAlistair Francis 			msecs_to_jiffies(CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS));
618*5b0c03e2SAlistair Francis 	if (rc <= 0) {
619*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "HID get descriptor timed out\n");
620*5b0c03e2SAlistair Francis 		rc = -ETIMEDOUT;
621*5b0c03e2SAlistair Francis 		return rc;
622*5b0c03e2SAlistair Francis 	}
623*5b0c03e2SAlistair Francis 
624*5b0c03e2SAlistair Francis 	memcpy(desc, ts->response_buf, sizeof(*desc));
625*5b0c03e2SAlistair Francis 
626*5b0c03e2SAlistair Francis 	/* Check HID descriptor length and version */
627*5b0c03e2SAlistair Francis 	if (le16_to_cpu(desc->hid_desc_len) != sizeof(*desc) ||
628*5b0c03e2SAlistair Francis 	    le16_to_cpu(desc->bcd_version) != HID_VERSION) {
629*5b0c03e2SAlistair Francis 		dev_err(dev, "Unsupported HID version\n");
630*5b0c03e2SAlistair Francis 		return -ENODEV;
631*5b0c03e2SAlistair Francis 	}
632*5b0c03e2SAlistair Francis 
633*5b0c03e2SAlistair Francis 	return 0;
634*5b0c03e2SAlistair Francis }
635*5b0c03e2SAlistair Francis 
636*5b0c03e2SAlistair Francis static int fill_tch_abs(struct cyttsp5_tch_abs_params *tch_abs, int report_size,
637*5b0c03e2SAlistair Francis 			int offset)
638*5b0c03e2SAlistair Francis {
639*5b0c03e2SAlistair Francis 	tch_abs->ofs = offset / 8;
640*5b0c03e2SAlistair Francis 	tch_abs->size = report_size / 8;
641*5b0c03e2SAlistair Francis 	if (report_size % 8)
642*5b0c03e2SAlistair Francis 		tch_abs->size += 1;
643*5b0c03e2SAlistair Francis 	tch_abs->min = 0;
644*5b0c03e2SAlistair Francis 	tch_abs->max = 1 << report_size;
645*5b0c03e2SAlistair Francis 	tch_abs->bofs = offset - (tch_abs->ofs << 3);
646*5b0c03e2SAlistair Francis 
647*5b0c03e2SAlistair Francis 	return 0;
648*5b0c03e2SAlistair Francis }
649*5b0c03e2SAlistair Francis 
650*5b0c03e2SAlistair Francis static irqreturn_t cyttsp5_handle_irq(int irq, void *handle)
651*5b0c03e2SAlistair Francis {
652*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = handle;
653*5b0c03e2SAlistair Francis 	int report_id;
654*5b0c03e2SAlistair Francis 	int size;
655*5b0c03e2SAlistair Francis 	int error;
656*5b0c03e2SAlistair Francis 
657*5b0c03e2SAlistair Francis 	error = cyttsp5_read(ts, ts->input_buf, CY_MAX_INPUT);
658*5b0c03e2SAlistair Francis 	if (error)
659*5b0c03e2SAlistair Francis 		return IRQ_HANDLED;
660*5b0c03e2SAlistair Francis 
661*5b0c03e2SAlistair Francis 	size = get_unaligned_le16(&ts->input_buf[0]);
662*5b0c03e2SAlistair Francis 	if (size == 0) {
663*5b0c03e2SAlistair Francis 		/* reset */
664*5b0c03e2SAlistair Francis 		report_id = 0;
665*5b0c03e2SAlistair Francis 		size = 2;
666*5b0c03e2SAlistair Francis 	} else {
667*5b0c03e2SAlistair Francis 		report_id = ts->input_buf[2];
668*5b0c03e2SAlistair Francis 	}
669*5b0c03e2SAlistair Francis 
670*5b0c03e2SAlistair Francis 	switch (report_id) {
671*5b0c03e2SAlistair Francis 	case HID_TOUCH_REPORT_ID:
672*5b0c03e2SAlistair Francis 		cyttsp5_mt_attention(ts->dev);
673*5b0c03e2SAlistair Francis 		break;
674*5b0c03e2SAlistair Francis 	case HID_BTN_REPORT_ID:
675*5b0c03e2SAlistair Francis 		cyttsp5_btn_attention(ts->dev);
676*5b0c03e2SAlistair Francis 		break;
677*5b0c03e2SAlistair Francis 	default:
678*5b0c03e2SAlistair Francis 		/* It is not an input but a command response */
679*5b0c03e2SAlistair Francis 		memcpy(ts->response_buf, ts->input_buf, size);
680*5b0c03e2SAlistair Francis 		complete(&ts->cmd_done);
681*5b0c03e2SAlistair Francis 	}
682*5b0c03e2SAlistair Francis 
683*5b0c03e2SAlistair Francis 	return IRQ_HANDLED;
684*5b0c03e2SAlistair Francis }
685*5b0c03e2SAlistair Francis 
686*5b0c03e2SAlistair Francis static int cyttsp5_deassert_int(struct cyttsp5 *ts)
687*5b0c03e2SAlistair Francis {
688*5b0c03e2SAlistair Francis 	u16 size;
689*5b0c03e2SAlistair Francis 	u8 buf[2];
690*5b0c03e2SAlistair Francis 	int error;
691*5b0c03e2SAlistair Francis 
692*5b0c03e2SAlistair Francis 	error = regmap_bulk_read(ts->regmap, HID_INPUT_REG, buf, sizeof(buf));
693*5b0c03e2SAlistair Francis 	if (error < 0)
694*5b0c03e2SAlistair Francis 		return error;
695*5b0c03e2SAlistair Francis 
696*5b0c03e2SAlistair Francis 	size = get_unaligned_le16(&buf[0]);
697*5b0c03e2SAlistair Francis 	if (size == 2 || size == 0)
698*5b0c03e2SAlistair Francis 		return 0;
699*5b0c03e2SAlistair Francis 
700*5b0c03e2SAlistair Francis 	return -EINVAL;
701*5b0c03e2SAlistair Francis }
702*5b0c03e2SAlistair Francis 
703*5b0c03e2SAlistair Francis static int cyttsp5_fill_all_touch(struct cyttsp5 *ts)
704*5b0c03e2SAlistair Francis {
705*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si = &ts->sysinfo;
706*5b0c03e2SAlistair Francis 
707*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_X], REPORT_SIZE_16,
708*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_X);
709*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_Y], REPORT_SIZE_16,
710*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_Y);
711*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_P], REPORT_SIZE_8,
712*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_P);
713*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_T], REPORT_SIZE_5,
714*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_CONTACTID);
715*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_hdr, REPORT_SIZE_5,
716*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_HDR_CONTACTCOUNT);
717*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_MAJ], REPORT_SIZE_8,
718*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_MAJ);
719*5b0c03e2SAlistair Francis 	fill_tch_abs(&si->tch_abs[CY_TCH_MIN], REPORT_SIZE_8,
720*5b0c03e2SAlistair Francis 		     TOUCH_REPORT_DESC_MIN);
721*5b0c03e2SAlistair Francis 
722*5b0c03e2SAlistair Francis 	return 0;
723*5b0c03e2SAlistair Francis }
724*5b0c03e2SAlistair Francis 
725*5b0c03e2SAlistair Francis static int cyttsp5_startup(struct cyttsp5 *ts)
726*5b0c03e2SAlistair Francis {
727*5b0c03e2SAlistair Francis 	int error;
728*5b0c03e2SAlistair Francis 
729*5b0c03e2SAlistair Francis 	error = cyttsp5_deassert_int(ts);
730*5b0c03e2SAlistair Francis 	if (error) {
731*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error on deassert int r=%d\n", error);
732*5b0c03e2SAlistair Francis 		return -ENODEV;
733*5b0c03e2SAlistair Francis 	}
734*5b0c03e2SAlistair Francis 
735*5b0c03e2SAlistair Francis 	/*
736*5b0c03e2SAlistair Francis 	 * Launch the application as the device starts in bootloader mode
737*5b0c03e2SAlistair Francis 	 * because of a power-on-reset
738*5b0c03e2SAlistair Francis 	 */
739*5b0c03e2SAlistair Francis 	error = cyttsp5_hid_output_bl_launch_app(ts);
740*5b0c03e2SAlistair Francis 	if (error < 0) {
741*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error on launch app r=%d\n", error);
742*5b0c03e2SAlistair Francis 		return error;
743*5b0c03e2SAlistair Francis 	}
744*5b0c03e2SAlistair Francis 
745*5b0c03e2SAlistair Francis 	error = cyttsp5_get_hid_descriptor(ts, &ts->hid_desc);
746*5b0c03e2SAlistair Francis 	if (error < 0) {
747*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error on getting HID descriptor r=%d\n", error);
748*5b0c03e2SAlistair Francis 		return error;
749*5b0c03e2SAlistair Francis 	}
750*5b0c03e2SAlistair Francis 
751*5b0c03e2SAlistair Francis 	error = cyttsp5_fill_all_touch(ts);
752*5b0c03e2SAlistair Francis 	if (error < 0) {
753*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error on report descriptor r=%d\n", error);
754*5b0c03e2SAlistair Francis 		return error;
755*5b0c03e2SAlistair Francis 	}
756*5b0c03e2SAlistair Francis 
757*5b0c03e2SAlistair Francis 	error = cyttsp5_hid_output_get_sysinfo(ts);
758*5b0c03e2SAlistair Francis 	if (error) {
759*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error on getting sysinfo r=%d\n", error);
760*5b0c03e2SAlistair Francis 		return error;
761*5b0c03e2SAlistair Francis 	}
762*5b0c03e2SAlistair Francis 
763*5b0c03e2SAlistair Francis 	return error;
764*5b0c03e2SAlistair Francis }
765*5b0c03e2SAlistair Francis 
766*5b0c03e2SAlistair Francis static void cyttsp5_cleanup(void *data)
767*5b0c03e2SAlistair Francis {
768*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts = data;
769*5b0c03e2SAlistair Francis 
770*5b0c03e2SAlistair Francis 	regulator_disable(ts->vdd);
771*5b0c03e2SAlistair Francis }
772*5b0c03e2SAlistair Francis 
773*5b0c03e2SAlistair Francis static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
774*5b0c03e2SAlistair Francis 			 const char *name)
775*5b0c03e2SAlistair Francis {
776*5b0c03e2SAlistair Francis 	struct cyttsp5 *ts;
777*5b0c03e2SAlistair Francis 	struct cyttsp5_sysinfo *si;
778*5b0c03e2SAlistair Francis 	int error, i;
779*5b0c03e2SAlistair Francis 
780*5b0c03e2SAlistair Francis 	ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
781*5b0c03e2SAlistair Francis 	if (!ts)
782*5b0c03e2SAlistair Francis 		return -ENOMEM;
783*5b0c03e2SAlistair Francis 
784*5b0c03e2SAlistair Francis 	/* Initialize device info */
785*5b0c03e2SAlistair Francis 	ts->regmap = regmap;
786*5b0c03e2SAlistair Francis 	ts->dev = dev;
787*5b0c03e2SAlistair Francis 	si = &ts->sysinfo;
788*5b0c03e2SAlistair Francis 	dev_set_drvdata(dev, ts);
789*5b0c03e2SAlistair Francis 
790*5b0c03e2SAlistair Francis 	init_completion(&ts->cmd_done);
791*5b0c03e2SAlistair Francis 
792*5b0c03e2SAlistair Francis 	/* Power up the device */
793*5b0c03e2SAlistair Francis 	ts->vdd = devm_regulator_get(dev, "vdd");
794*5b0c03e2SAlistair Francis 	if (IS_ERR(ts->vdd)) {
795*5b0c03e2SAlistair Francis 		error = PTR_ERR(ts->vdd);
796*5b0c03e2SAlistair Francis 		return error;
797*5b0c03e2SAlistair Francis 	}
798*5b0c03e2SAlistair Francis 
799*5b0c03e2SAlistair Francis 	error = devm_add_action_or_reset(dev, cyttsp5_cleanup, ts);
800*5b0c03e2SAlistair Francis 	if (error)
801*5b0c03e2SAlistair Francis 		return error;
802*5b0c03e2SAlistair Francis 
803*5b0c03e2SAlistair Francis 	error = regulator_enable(ts->vdd);
804*5b0c03e2SAlistair Francis 	if (error)
805*5b0c03e2SAlistair Francis 		return error;
806*5b0c03e2SAlistair Francis 
807*5b0c03e2SAlistair Francis 	ts->input = devm_input_allocate_device(dev);
808*5b0c03e2SAlistair Francis 	if (!ts->input) {
809*5b0c03e2SAlistair Francis 		dev_err(dev, "Error, failed to allocate input device\n");
810*5b0c03e2SAlistair Francis 		return -ENODEV;
811*5b0c03e2SAlistair Francis 	}
812*5b0c03e2SAlistair Francis 
813*5b0c03e2SAlistair Francis 	ts->input->name = "cyttsp5";
814*5b0c03e2SAlistair Francis 	scnprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
815*5b0c03e2SAlistair Francis 	ts->input->phys = ts->phys;
816*5b0c03e2SAlistair Francis 	input_set_drvdata(ts->input, ts);
817*5b0c03e2SAlistair Francis 
818*5b0c03e2SAlistair Francis 	/* Reset the gpio to be in a reset state */
819*5b0c03e2SAlistair Francis 	ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
820*5b0c03e2SAlistair Francis 	if (IS_ERR(ts->reset_gpio)) {
821*5b0c03e2SAlistair Francis 		error = PTR_ERR(ts->reset_gpio);
822*5b0c03e2SAlistair Francis 		dev_err(dev, "Failed to request reset gpio, error %d\n", error);
823*5b0c03e2SAlistair Francis 		return error;
824*5b0c03e2SAlistair Francis 	}
825*5b0c03e2SAlistair Francis 	gpiod_set_value_cansleep(ts->reset_gpio, 0);
826*5b0c03e2SAlistair Francis 
827*5b0c03e2SAlistair Francis 	/* Need a delay to have device up */
828*5b0c03e2SAlistair Francis 	msleep(20);
829*5b0c03e2SAlistair Francis 
830*5b0c03e2SAlistair Francis 	error = devm_request_threaded_irq(dev, irq, NULL, cyttsp5_handle_irq,
831*5b0c03e2SAlistair Francis 					  IRQF_ONESHOT, name, ts);
832*5b0c03e2SAlistair Francis 	if (error) {
833*5b0c03e2SAlistair Francis 		dev_err(dev, "unable to request IRQ\n");
834*5b0c03e2SAlistair Francis 		return error;
835*5b0c03e2SAlistair Francis 	}
836*5b0c03e2SAlistair Francis 
837*5b0c03e2SAlistair Francis 	error = cyttsp5_startup(ts);
838*5b0c03e2SAlistair Francis 	if (error) {
839*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Fail initial startup r=%d\n", error);
840*5b0c03e2SAlistair Francis 		return error;
841*5b0c03e2SAlistair Francis 	}
842*5b0c03e2SAlistair Francis 
843*5b0c03e2SAlistair Francis 	error = cyttsp5_parse_dt_key_code(dev);
844*5b0c03e2SAlistair Francis 	if (error < 0) {
845*5b0c03e2SAlistair Francis 		dev_err(ts->dev, "Error while parsing dts %d\n", error);
846*5b0c03e2SAlistair Francis 		return error;
847*5b0c03e2SAlistair Francis 	}
848*5b0c03e2SAlistair Francis 
849*5b0c03e2SAlistair Francis 	touchscreen_parse_properties(ts->input, true, &ts->prop);
850*5b0c03e2SAlistair Francis 
851*5b0c03e2SAlistair Francis 	__set_bit(EV_KEY, ts->input->evbit);
852*5b0c03e2SAlistair Francis 	for (i = 0; i < si->num_btns; i++)
853*5b0c03e2SAlistair Francis 		__set_bit(si->key_code[i], ts->input->keybit);
854*5b0c03e2SAlistair Francis 
855*5b0c03e2SAlistair Francis 	return cyttsp5_setup_input_device(dev);
856*5b0c03e2SAlistair Francis }
857*5b0c03e2SAlistair Francis 
858*5b0c03e2SAlistair Francis static int cyttsp5_i2c_probe(struct i2c_client *client,
859*5b0c03e2SAlistair Francis 			     const struct i2c_device_id *id)
860*5b0c03e2SAlistair Francis {
861*5b0c03e2SAlistair Francis 	struct regmap *regmap;
862*5b0c03e2SAlistair Francis 	static const struct regmap_config config = {
863*5b0c03e2SAlistair Francis 		.reg_bits = 8,
864*5b0c03e2SAlistair Francis 		.val_bits = 8,
865*5b0c03e2SAlistair Francis 	};
866*5b0c03e2SAlistair Francis 
867*5b0c03e2SAlistair Francis 	regmap = devm_regmap_init_i2c(client, &config);
868*5b0c03e2SAlistair Francis 	if (IS_ERR(regmap)) {
869*5b0c03e2SAlistair Francis 		dev_err(&client->dev, "regmap allocation failed: %ld\n",
870*5b0c03e2SAlistair Francis 			PTR_ERR(regmap));
871*5b0c03e2SAlistair Francis 		return PTR_ERR(regmap);
872*5b0c03e2SAlistair Francis 	}
873*5b0c03e2SAlistair Francis 
874*5b0c03e2SAlistair Francis 	return cyttsp5_probe(&client->dev, regmap, client->irq, client->name);
875*5b0c03e2SAlistair Francis }
876*5b0c03e2SAlistair Francis 
877*5b0c03e2SAlistair Francis static const struct of_device_id cyttsp5_of_match[] = {
878*5b0c03e2SAlistair Francis 	{ .compatible = "cypress,tt21000", },
879*5b0c03e2SAlistair Francis 	{ }
880*5b0c03e2SAlistair Francis };
881*5b0c03e2SAlistair Francis MODULE_DEVICE_TABLE(of, cyttsp5_of_match);
882*5b0c03e2SAlistair Francis 
883*5b0c03e2SAlistair Francis static const struct i2c_device_id cyttsp5_i2c_id[] = {
884*5b0c03e2SAlistair Francis 	{ CYTTSP5_NAME, 0, },
885*5b0c03e2SAlistair Francis 	{ }
886*5b0c03e2SAlistair Francis };
887*5b0c03e2SAlistair Francis MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
888*5b0c03e2SAlistair Francis 
889*5b0c03e2SAlistair Francis static struct i2c_driver cyttsp5_i2c_driver = {
890*5b0c03e2SAlistair Francis 	.driver = {
891*5b0c03e2SAlistair Francis 		.name = CYTTSP5_NAME,
892*5b0c03e2SAlistair Francis 		.of_match_table = cyttsp5_of_match,
893*5b0c03e2SAlistair Francis 	},
894*5b0c03e2SAlistair Francis 	.probe = cyttsp5_i2c_probe,
895*5b0c03e2SAlistair Francis 	.id_table = cyttsp5_i2c_id,
896*5b0c03e2SAlistair Francis };
897*5b0c03e2SAlistair Francis module_i2c_driver(cyttsp5_i2c_driver);
898*5b0c03e2SAlistair Francis 
899*5b0c03e2SAlistair Francis MODULE_LICENSE("GPL");
900*5b0c03e2SAlistair Francis MODULE_DESCRIPTION("Touchscreen driver for Cypress TrueTouch Gen 5 Product");
901*5b0c03e2SAlistair Francis MODULE_AUTHOR("Mylène Josserand <mylene.josserand@bootlin.com>");
902