xref: /openbmc/linux/drivers/input/mouse/cyapa_gen5.c (revision 6972a859)
1 /*
2  * Cypress APA trackpad with I2C interface
3  *
4  * Author: Dudley Du <dudl@cypress.com>
5  *
6  * Copyright (C) 2014 Cypress Semiconductor, Inc.
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file COPYING in the main directory of this archive for
10  * more details.
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/i2c.h>
15 #include <linux/input.h>
16 #include <linux/input/mt.h>
17 #include <linux/mutex.h>
18 #include <linux/completion.h>
19 #include <linux/slab.h>
20 #include <linux/unaligned/access_ok.h>
21 #include "cyapa.h"
22 
23 
24 /* Macro of Gen5 */
25 #define RECORD_EVENT_NONE        0
26 #define RECORD_EVENT_TOUCHDOWN	 1
27 #define RECORD_EVENT_DISPLACE    2
28 #define RECORD_EVENT_LIFTOFF     3
29 
30 #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE      0x80
31 #define CYAPA_TSG_IMG_FW_HDR_SIZE           13
32 #define CYAPA_TSG_FW_ROW_SIZE               (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
33 #define CYAPA_TSG_IMG_START_ROW_NUM         0x002e
34 #define CYAPA_TSG_IMG_END_ROW_NUM           0x01fe
35 #define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
36 #define CYAPA_TSG_IMG_MAX_RECORDS           (CYAPA_TSG_IMG_END_ROW_NUM - \
37 				CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
38 #define CYAPA_TSG_IMG_READ_SIZE             (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
39 #define CYAPA_TSG_START_OF_APPLICATION      0x1700
40 #define CYAPA_TSG_APP_INTEGRITY_SIZE        60
41 #define CYAPA_TSG_FLASH_MAP_METADATA_SIZE   60
42 #define CYAPA_TSG_BL_KEY_SIZE               8
43 
44 #define CYAPA_TSG_MAX_CMD_SIZE              256
45 
46 #define GEN5_BL_CMD_VERIFY_APP_INTEGRITY    0x31
47 #define GEN5_BL_CMD_GET_BL_INFO		    0x38
48 #define GEN5_BL_CMD_PROGRAM_VERIFY_ROW      0x39
49 #define GEN5_BL_CMD_LAUNCH_APP		    0x3b
50 #define GEN5_BL_CMD_INITIATE_BL		    0x48
51 
52 #define GEN5_HID_DESCRIPTOR_ADDR	0x0001
53 #define GEN5_REPORT_DESCRIPTOR_ADDR	0x0002
54 #define GEN5_INPUT_REPORT_ADDR		0x0003
55 #define GEN5_OUTPUT_REPORT_ADDR		0x0004
56 #define GEN5_CMD_DATA_ADDR		0x0006
57 
58 #define GEN5_TOUCH_REPORT_HEAD_SIZE     7
59 #define GEN5_TOUCH_REPORT_MAX_SIZE      127
60 #define GEN5_BTN_REPORT_HEAD_SIZE       6
61 #define GEN5_BTN_REPORT_MAX_SIZE        14
62 #define GEN5_WAKEUP_EVENT_SIZE          4
63 #define GEN5_RAW_DATA_HEAD_SIZE         24
64 
65 #define GEN5_BL_CMD_REPORT_ID           0x40
66 #define GEN5_BL_RESP_REPORT_ID          0x30
67 #define GEN5_APP_CMD_REPORT_ID          0x2f
68 #define GEN5_APP_RESP_REPORT_ID         0x1f
69 
70 #define GEN5_APP_DEEP_SLEEP_REPORT_ID   0xf0
71 #define GEN5_DEEP_SLEEP_RESP_LENGTH     5
72 
73 #define GEN5_CMD_GET_PARAMETER		     0x05
74 #define GEN5_CMD_SET_PARAMETER		     0x06
75 #define GEN5_PARAMETER_ACT_INTERVL_ID        0x4d
76 #define GEN5_PARAMETER_ACT_INTERVL_SIZE      1
77 #define GEN5_PARAMETER_ACT_LFT_INTERVL_ID    0x4f
78 #define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE  2
79 #define GEN5_PARAMETER_LP_INTRVL_ID          0x4c
80 #define GEN5_PARAMETER_LP_INTRVL_SIZE        2
81 
82 #define GEN5_PARAMETER_DISABLE_PIP_REPORT    0x08
83 
84 #define GEN5_POWER_STATE_ACTIVE              0x01
85 #define GEN5_POWER_STATE_LOOK_FOR_TOUCH      0x02
86 #define GEN5_POWER_STATE_READY               0x03
87 #define GEN5_POWER_STATE_IDLE                0x04
88 #define GEN5_POWER_STATE_BTN_ONLY            0x05
89 #define GEN5_POWER_STATE_OFF                 0x06
90 
91 #define GEN5_DEEP_SLEEP_STATE_MASK  0x03
92 #define GEN5_DEEP_SLEEP_STATE_ON    0x00
93 #define GEN5_DEEP_SLEEP_STATE_OFF   0x01
94 
95 #define GEN5_DEEP_SLEEP_OPCODE      0x08
96 #define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
97 
98 #define GEN5_POWER_READY_MAX_INTRVL_TIME  50   /* Unit: ms */
99 #define GEN5_POWER_IDLE_MAX_INTRVL_TIME   250  /* Unit: ms */
100 
101 #define GEN5_CMD_REPORT_ID_OFFSET       4
102 
103 #define GEN5_RESP_REPORT_ID_OFFSET      2
104 #define GEN5_RESP_RSVD_OFFSET           3
105 #define     GEN5_RESP_RSVD_KEY          0x00
106 #define GEN5_RESP_BL_SOP_OFFSET         4
107 #define     GEN5_SOP_KEY                0x01  /* Start of Packet */
108 #define     GEN5_EOP_KEY                0x17  /* End of Packet */
109 #define GEN5_RESP_APP_CMD_OFFSET        4
110 #define     GET_GEN5_CMD_CODE(reg)      ((reg) & 0x7f)
111 
112 #define VALID_CMD_RESP_HEADER(resp, cmd)				    \
113 	(((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \
114 	((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) &&	    \
115 	(GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd)))
116 
117 #define GEN5_MIN_BL_CMD_LENGTH           13
118 #define GEN5_MIN_BL_RESP_LENGTH          11
119 #define GEN5_MIN_APP_CMD_LENGTH          7
120 #define GEN5_MIN_APP_RESP_LENGTH         5
121 #define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6
122 
123 #define GEN5_RESP_LENGTH_OFFSET  0x00
124 #define GEN5_RESP_LENGTH_SIZE    2
125 
126 #define GEN5_HID_DESCRIPTOR_SIZE      32
127 #define GEN5_BL_HID_REPORT_ID         0xff
128 #define GEN5_APP_HID_REPORT_ID        0xf7
129 #define GEN5_BL_MAX_OUTPUT_LENGTH     0x0100
130 #define GEN5_APP_MAX_OUTPUT_LENGTH    0x00fe
131 
132 #define GEN5_BL_REPORT_DESCRIPTOR_SIZE            0x1d
133 #define GEN5_BL_REPORT_DESCRIPTOR_ID              0xfe
134 #define GEN5_APP_REPORT_DESCRIPTOR_SIZE           0xee
135 #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE  0xfa
136 #define GEN5_APP_REPORT_DESCRIPTOR_ID             0xf6
137 
138 #define GEN5_TOUCH_REPORT_ID         0x01
139 #define GEN5_BTN_REPORT_ID           0x03
140 #define GEN5_WAKEUP_EVENT_REPORT_ID  0x04
141 #define GEN5_OLD_PUSH_BTN_REPORT_ID  0x05
142 #define GEN5_PUSH_BTN_REPORT_ID      0x06
143 
144 #define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
145 
146 #define GEN5_BL_INITIATE_RESP_LEN            11
147 #define GEN5_BL_FAIL_EXIT_RESP_LEN           11
148 #define GEN5_BL_FAIL_EXIT_STATUS_CODE        0x0c
149 #define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN    12
150 #define GEN5_BL_INTEGRITY_CHEKC_PASS         0x00
151 #define GEN5_BL_BLOCK_WRITE_RESP_LEN         11
152 #define GEN5_BL_READ_APP_INFO_RESP_LEN       31
153 #define GEN5_CMD_CALIBRATE                   0x28
154 #define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE   0x00
155 #define CYAPA_SENSING_MODE_SELF_CAP          0x02
156 
157 #define GEN5_CMD_RETRIEVE_DATA_STRUCTURE     0x24
158 #define GEN5_RETRIEVE_MUTUAL_PWC_DATA        0x00
159 #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA      0x01
160 
161 #define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
162 
163 #define GEN5_CMD_EXECUTE_PANEL_SCAN          0x2a
164 #define GEN5_CMD_RETRIEVE_PANEL_SCAN         0x2b
165 #define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA      0x00
166 #define GEN5_PANEL_SCAN_MUTUAL_BASELINE      0x01
167 #define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT     0x02
168 #define GEN5_PANEL_SCAN_SELF_RAW_DATA        0x03
169 #define GEN5_PANEL_SCAN_SELF_BASELINE        0x04
170 #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT       0x05
171 
172 /* The offset only valid for reterive PWC and panel scan commands */
173 #define GEN5_RESP_DATA_STRUCTURE_OFFSET      10
174 #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK      0x07
175 
176 #define	GEN5_NUMBER_OF_TOUCH_OFFSET  5
177 #define GEN5_NUMBER_OF_TOUCH_MASK    0x1f
178 #define GEN5_BUTTONS_OFFSET          5
179 #define GEN5_BUTTONS_MASK            0x0f
180 #define GEN5_GET_EVENT_ID(reg)       (((reg) >> 5) & 0x03)
181 #define GEN5_GET_TOUCH_ID(reg)       ((reg) & 0x1f)
182 
183 #define GEN5_PRODUCT_FAMILY_MASK        0xf000
184 #define GEN5_PRODUCT_FAMILY_TRACKPAD    0x1000
185 
186 #define TSG_INVALID_CMD   0xff
187 
188 struct cyapa_gen5_touch_record {
189 	/*
190 	 * Bit 7 - 3: reserved
191 	 * Bit 2 - 0: touch type;
192 	 *            0 : standard finger;
193 	 *            1 - 15 : reserved.
194 	 */
195 	u8 touch_type;
196 
197 	/*
198 	 * Bit 7: indicates touch liftoff status.
199 	 *		0 : touch is currently on the panel.
200 	 *		1 : touch record indicates a liftoff.
201 	 * Bit 6 - 5: indicates an event associated with this touch instance
202 	 *		0 : no event
203 	 *		1 : touchdown
204 	 *		2 : significant displacement (> active distance)
205 	 *		3 : liftoff (record reports last known coordinates)
206 	 * Bit 4 - 0: An arbitrary ID tag associated with a finger
207 	 *		to allow tracking a touch as it moves around the panel.
208 	 */
209 	u8 touch_tip_event_id;
210 
211 	/* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
212 	u8 x_lo;
213 
214 	/* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
215 	u8 x_hi;
216 
217 	/* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
218 	u8 y_lo;
219 
220 	/* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
221 	u8 y_hi;
222 
223 	/* Touch intensity in counts, pressure value. */
224 	u8 z;
225 
226 	/*
227 	 * The length of the major axis of the ellipse of contact between
228 	 * the finger and the panel (ABS_MT_TOUCH_MAJOR).
229 	 */
230 	u8 major_axis_len;
231 
232 	/*
233 	 * The length of the minor axis of the ellipse of contact between
234 	 * the finger and the panel (ABS_MT_TOUCH_MINOR).
235 	 */
236 	u8 minor_axis_len;
237 
238 	/*
239 	 * The length of the major axis of the approaching tool.
240 	 * (ABS_MT_WIDTH_MAJOR)
241 	 */
242 	u8 major_tool_len;
243 
244 	/*
245 	 * The length of the minor axis of the approaching tool.
246 	 * (ABS_MT_WIDTH_MINOR)
247 	 */
248 	u8 minor_tool_len;
249 
250 	/*
251 	 * The angle between the panel vertical axis and
252 	 * the major axis of the contact ellipse. This value is an 8-bit
253 	 * signed integer. The range is -127 to +127 (corresponding to
254 	 * -90 degree and +90 degree respectively).
255 	 * The positive direction is clockwise from the vertical axis.
256 	 * If the ellipse of contact degenerates into a circle,
257 	 * orientation is reported as 0.
258 	 */
259 	u8 orientation;
260 } __packed;
261 
262 struct cyapa_gen5_report_data {
263 	u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE];
264 	struct cyapa_gen5_touch_record touch_records[10];
265 } __packed;
266 
267 struct gen5_app_cmd_head {
268 	__le16 addr;   /* Output report register address, must be 0004h */
269 	/* Size of packet not including output report register address */
270 	__le16 length;
271 	u8 report_id;  /* Application output report id, must be 2Fh */
272 	u8 rsvd;  /* Reserved, must be 0 */
273 	/*
274 	 * Bit 7: reserved, must be 0.
275 	 * Bit 6-0: command code.
276 	 */
277 	u8 cmd_code;
278 	u8 parameter_data[0];  /* Parameter data variable based on cmd_code */
279 } __packed;
280 
281 /* Applicaton get/set parameter command data structure */
282 struct gen5_app_set_parameter_data {
283 	u8 parameter_id;
284 	u8 parameter_size;
285 	__le32 value;
286 } __packed;
287 
288 struct gen5_app_get_parameter_data {
289 	u8 parameter_id;
290 } __packed;
291 
292 /* Variables to record latest gen5 trackpad power states. */
293 #define GEN5_DEV_SET_PWR_STATE(cyapa, s)	((cyapa)->dev_pwr_mode = (s))
294 #define GEN5_DEV_GET_PWR_STATE(cyapa)		((cyapa)->dev_pwr_mode)
295 #define GEN5_DEV_SET_SLEEP_TIME(cyapa, t)	((cyapa)->dev_sleep_time = (t))
296 #define GEN5_DEV_GET_SLEEP_TIME(cyapa)		((cyapa)->dev_sleep_time)
297 #define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa)	\
298 		(((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME)
299 
300 static int cyapa_gen5_initialize(struct cyapa *cyapa)
301 {
302 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
303 
304 	init_completion(&gen5_pip->cmd_ready);
305 	atomic_set(&gen5_pip->cmd_issued, 0);
306 	mutex_init(&gen5_pip->cmd_lock);
307 
308 	gen5_pip->resp_sort_func = NULL;
309 	gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
310 	gen5_pip->resp_data = NULL;
311 	gen5_pip->resp_len = NULL;
312 
313 	cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
314 	cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
315 
316 	return 0;
317 }
318 
319 /* Return negative errno, or else the number of bytes read. */
320 static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
321 {
322 	int ret;
323 
324 	if (size == 0)
325 		return 0;
326 
327 	if (!buf || size > CYAPA_REG_MAP_SIZE)
328 		return -EINVAL;
329 
330 	ret = i2c_master_recv(cyapa->client, buf, size);
331 
332 	if (ret != size)
333 		return (ret < 0) ? ret : -EIO;
334 
335 	return size;
336 }
337 
338 /**
339  * Return a negative errno code else zero on success.
340  */
341 static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
342 {
343 	int ret;
344 
345 	if (!buf || !size)
346 		return -EINVAL;
347 
348 	ret = i2c_master_send(cyapa->client, buf, size);
349 
350 	if (ret != size)
351 		return (ret < 0) ? ret : -EIO;
352 
353 	return 0;
354 }
355 
356 /**
357  * This function is aimed to dump all not read data in Gen5 trackpad
358  * before send any command, otherwise, the interrupt line will be blocked.
359  */
360 static int cyapa_empty_pip_output_data(struct cyapa *cyapa,
361 		u8 *buf, int *len, cb_sort func)
362 {
363 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
364 	int length;
365 	int report_count;
366 	int empty_count;
367 	int buf_len;
368 	int error;
369 
370 	buf_len = 0;
371 	if (len) {
372 		buf_len = (*len < CYAPA_REG_MAP_SIZE) ?
373 				*len : CYAPA_REG_MAP_SIZE;
374 		*len = 0;
375 	}
376 
377 	report_count = 8;  /* max 7 pending data before command response data */
378 	empty_count = 0;
379 	do {
380 		/*
381 		 * Depending on testing in cyapa driver, there are max 5 "02 00"
382 		 * packets between two valid buffered data report in firmware.
383 		 * So in order to dump all buffered data out and
384 		 * make interrupt line release for reassert again,
385 		 * we must set the empty_count check value bigger than 5 to
386 		 * make it work. Otherwise, in some situation,
387 		 * the interrupt line may unable to reactive again,
388 		 * which will cause trackpad device unable to
389 		 * report data any more.
390 		 * for example, it may happen in EFT and ESD testing.
391 		 */
392 		if (empty_count > 5)
393 			return 0;
394 
395 		error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf,
396 				GEN5_RESP_LENGTH_SIZE);
397 		if (error < 0)
398 			return error;
399 
400 		length = get_unaligned_le16(gen5_pip->empty_buf);
401 		if (length == GEN5_RESP_LENGTH_SIZE) {
402 			empty_count++;
403 			continue;
404 		} else if (length > CYAPA_REG_MAP_SIZE) {
405 			/* Should not happen */
406 			return -EINVAL;
407 		} else if (length == 0) {
408 			/* Application or bootloader launch data polled out. */
409 			length = GEN5_RESP_LENGTH_SIZE;
410 			if (buf && buf_len && func &&
411 				func(cyapa, gen5_pip->empty_buf, length)) {
412 				length = min(buf_len, length);
413 				memcpy(buf, gen5_pip->empty_buf, length);
414 				*len = length;
415 				/* Response found, success. */
416 				return 0;
417 			}
418 			continue;
419 		}
420 
421 		error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
422 		if (error < 0)
423 			return error;
424 
425 		report_count--;
426 		empty_count = 0;
427 		length = get_unaligned_le16(gen5_pip->empty_buf);
428 		if (length <= GEN5_RESP_LENGTH_SIZE) {
429 			empty_count++;
430 		} else if (buf && buf_len && func &&
431 			func(cyapa, gen5_pip->empty_buf, length)) {
432 			length = min(buf_len, length);
433 			memcpy(buf, gen5_pip->empty_buf, length);
434 			*len = length;
435 			/* Response found, success. */
436 			return 0;
437 		}
438 
439 		error = -EINVAL;
440 	} while (report_count);
441 
442 	return error;
443 }
444 
445 static int cyapa_do_i2c_pip_cmd_irq_sync(
446 		struct cyapa *cyapa,
447 		u8 *cmd, size_t cmd_len,
448 		unsigned long timeout)
449 {
450 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
451 	int error;
452 
453 	/* Wait for interrupt to set ready completion */
454 	init_completion(&gen5_pip->cmd_ready);
455 
456 	atomic_inc(&gen5_pip->cmd_issued);
457 	error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
458 	if (error) {
459 		atomic_dec(&gen5_pip->cmd_issued);
460 		return (error < 0) ? error : -EIO;
461 	}
462 
463 	/* Wait for interrupt to indicate command is completed. */
464 	timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready,
465 				msecs_to_jiffies(timeout));
466 	if (timeout == 0) {
467 		atomic_dec(&gen5_pip->cmd_issued);
468 		return -ETIMEDOUT;
469 	}
470 
471 	return 0;
472 }
473 
474 static int cyapa_do_i2c_pip_cmd_polling(
475 		struct cyapa *cyapa,
476 		u8 *cmd, size_t cmd_len,
477 		u8 *resp_data, int *resp_len,
478 		unsigned long timeout,
479 		cb_sort func)
480 {
481 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
482 	int tries;
483 	int length;
484 	int error;
485 
486 	atomic_inc(&gen5_pip->cmd_issued);
487 	error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
488 	if (error) {
489 		atomic_dec(&gen5_pip->cmd_issued);
490 		return error < 0 ? error : -EIO;
491 	}
492 
493 	length = resp_len ? *resp_len : 0;
494 	if (resp_data && resp_len && length != 0 && func) {
495 		tries = timeout / 5;
496 		do {
497 			usleep_range(3000, 5000);
498 			*resp_len = length;
499 			error = cyapa_empty_pip_output_data(cyapa,
500 					resp_data, resp_len, func);
501 			if (error || *resp_len == 0)
502 				continue;
503 			else
504 				break;
505 		} while (--tries > 0);
506 		if ((error || *resp_len == 0) || tries <= 0)
507 			error = error ? error : -ETIMEDOUT;
508 	}
509 
510 	atomic_dec(&gen5_pip->cmd_issued);
511 	return error;
512 }
513 
514 static int cyapa_i2c_pip_cmd_irq_sync(
515 		struct cyapa *cyapa,
516 		u8 *cmd, int cmd_len,
517 		u8 *resp_data, int *resp_len,
518 		unsigned long timeout,
519 		cb_sort func,
520 		bool irq_mode)
521 {
522 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
523 	int error;
524 
525 	if (!cmd || !cmd_len)
526 		return -EINVAL;
527 
528 	/* Commands must be serialized. */
529 	error = mutex_lock_interruptible(&gen5_pip->cmd_lock);
530 	if (error)
531 		return error;
532 
533 	gen5_pip->resp_sort_func = func;
534 	gen5_pip->resp_data = resp_data;
535 	gen5_pip->resp_len = resp_len;
536 
537 	if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH &&
538 			cmd[4] == GEN5_APP_CMD_REPORT_ID) {
539 		/* Application command */
540 		gen5_pip->in_progress_cmd = cmd[6] & 0x7f;
541 	} else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH &&
542 			cmd[4] == GEN5_BL_CMD_REPORT_ID) {
543 		/* Bootloader command */
544 		gen5_pip->in_progress_cmd = cmd[7];
545 	}
546 
547 	/* Send command data, wait and read output response data's length. */
548 	if (irq_mode) {
549 		gen5_pip->is_irq_mode = true;
550 		error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
551 							timeout);
552 		if (error == -ETIMEDOUT && resp_data &&
553 				resp_len && *resp_len != 0 && func) {
554 			/*
555 			 * For some old version, there was no interrupt for
556 			 * the command response data, so need to poll here
557 			 * to try to get the response data.
558 			 */
559 			error = cyapa_empty_pip_output_data(cyapa,
560 					resp_data, resp_len, func);
561 			if (error || *resp_len == 0)
562 				error = error ? error : -ETIMEDOUT;
563 		}
564 	} else {
565 		gen5_pip->is_irq_mode = false;
566 		error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
567 				resp_data, resp_len, timeout, func);
568 	}
569 
570 	gen5_pip->resp_sort_func = NULL;
571 	gen5_pip->resp_data = NULL;
572 	gen5_pip->resp_len = NULL;
573 	gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
574 
575 	mutex_unlock(&gen5_pip->cmd_lock);
576 	return error;
577 }
578 
579 static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
580 		u8 *data, int len)
581 {
582 	if (!data || len < GEN5_MIN_BL_RESP_LENGTH)
583 		return false;
584 
585 	/* Bootloader input report id 30h */
586 	if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID &&
587 			data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
588 			data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY)
589 		return true;
590 
591 	return false;
592 }
593 
594 static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
595 		u8 *data, int len)
596 {
597 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
598 	int resp_len;
599 
600 	if (!data || len < GEN5_MIN_APP_RESP_LENGTH)
601 		return false;
602 
603 	if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID &&
604 			data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) {
605 		resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]);
606 		if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 &&
607 			resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH &&
608 			data[5] == gen5_pip->in_progress_cmd) {
609 			/* Unsupported command code */
610 			return false;
611 		} else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) ==
612 				gen5_pip->in_progress_cmd) {
613 			/* Correct command response received */
614 			return true;
615 		}
616 	}
617 
618 	return false;
619 }
620 
621 static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa,
622 		u8 *buf, int len)
623 {
624 	int resp_len;
625 	int max_output_len;
626 
627 	/* Check hid descriptor. */
628 	if (len != GEN5_HID_DESCRIPTOR_SIZE)
629 		return false;
630 
631 	resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]);
632 	max_output_len = get_unaligned_le16(&buf[16]);
633 	if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) {
634 		if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID &&
635 				max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
636 			/* BL mode HID Descriptor */
637 			return true;
638 		} else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] ==
639 				GEN5_APP_HID_REPORT_ID) &&
640 				max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
641 			/* APP mode HID Descriptor */
642 			return true;
643 		}
644 	}
645 
646 	return false;
647 }
648 
649 static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa,
650 		u8 *buf, int len)
651 {
652 	if (len == GEN5_DEEP_SLEEP_RESP_LENGTH &&
653 		buf[GEN5_RESP_REPORT_ID_OFFSET] ==
654 			GEN5_APP_DEEP_SLEEP_REPORT_ID &&
655 		(buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) ==
656 			GEN5_DEEP_SLEEP_OPCODE)
657 		return true;
658 	return false;
659 }
660 
661 static int gen5_idle_state_parse(struct cyapa *cyapa)
662 {
663 	u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE];
664 	int max_output_len;
665 	int length;
666 	u8 cmd[2];
667 	int ret;
668 	int error;
669 
670 	/*
671 	 * Dump all buffered data firstly for the situation
672 	 * when the trackpad is just power on the cyapa go here.
673 	 */
674 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
675 
676 	memset(resp_data, 0, sizeof(resp_data));
677 	ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
678 	if (ret != 3)
679 		return ret < 0 ? ret : -EIO;
680 
681 	length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
682 	if (length == GEN5_RESP_LENGTH_SIZE) {
683 		/* Normal state of Gen5 with no data to respose */
684 		cyapa->gen = CYAPA_GEN5;
685 
686 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
687 
688 		/* Read description from trackpad device */
689 		cmd[0] = 0x01;
690 		cmd[1] = 0x00;
691 		length = GEN5_HID_DESCRIPTOR_SIZE;
692 		error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
693 				cmd, GEN5_RESP_LENGTH_SIZE,
694 				resp_data, &length,
695 				300,
696 				cyapa_gen5_sort_hid_descriptor_data,
697 				false);
698 		if (error)
699 			return error;
700 
701 		length = get_unaligned_le16(
702 				&resp_data[GEN5_RESP_LENGTH_OFFSET]);
703 		max_output_len = get_unaligned_le16(&resp_data[16]);
704 		if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
705 				length == GEN5_RESP_LENGTH_SIZE) &&
706 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
707 				GEN5_BL_HID_REPORT_ID) &&
708 			max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
709 			/* BL mode HID Description read */
710 			cyapa->state = CYAPA_STATE_GEN5_BL;
711 		} else if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
712 				length == GEN5_RESP_LENGTH_SIZE) &&
713 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
714 				GEN5_APP_HID_REPORT_ID) &&
715 			max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
716 			/* APP mode HID Description read */
717 			cyapa->state = CYAPA_STATE_GEN5_APP;
718 		} else {
719 			/* Should not happen!!! */
720 			cyapa->state = CYAPA_STATE_NO_DEVICE;
721 		}
722 	}
723 
724 	return 0;
725 }
726 
727 static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
728 {
729 	int length;
730 	u8 resp_data[32];
731 	int max_output_len;
732 	int ret;
733 
734 	/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
735 	 * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
736 	 *
737 	 * Must read HID Description content through out,
738 	 * otherwise Gen5 trackpad cannot response next command
739 	 * or report any touch or button data.
740 	 */
741 	ret = cyapa_i2c_pip_read(cyapa, resp_data,
742 			GEN5_HID_DESCRIPTOR_SIZE);
743 	if (ret != GEN5_HID_DESCRIPTOR_SIZE)
744 		return ret < 0 ? ret : -EIO;
745 	length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
746 	max_output_len = get_unaligned_le16(&resp_data[16]);
747 	if (length == GEN5_RESP_LENGTH_SIZE) {
748 		if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
749 				GEN5_BL_HID_REPORT_ID) {
750 			/*
751 			 * BL mode HID Description has been previously
752 			 * read out.
753 			 */
754 			cyapa->gen = CYAPA_GEN5;
755 			cyapa->state = CYAPA_STATE_GEN5_BL;
756 		} else {
757 			/*
758 			 * APP mode HID Description has been previously
759 			 * read out.
760 			 */
761 			cyapa->gen = CYAPA_GEN5;
762 			cyapa->state = CYAPA_STATE_GEN5_APP;
763 		}
764 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
765 			resp_data[2] == GEN5_BL_HID_REPORT_ID &&
766 			max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
767 		/* BL mode HID Description read. */
768 		cyapa->gen = CYAPA_GEN5;
769 		cyapa->state = CYAPA_STATE_GEN5_BL;
770 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
771 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
772 				GEN5_APP_HID_REPORT_ID) &&
773 			max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
774 		/* APP mode HID Description read. */
775 		cyapa->gen = CYAPA_GEN5;
776 		cyapa->state = CYAPA_STATE_GEN5_APP;
777 	} else {
778 		/* Should not happen!!! */
779 		cyapa->state = CYAPA_STATE_NO_DEVICE;
780 	}
781 
782 	return 0;
783 }
784 
785 static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
786 {
787 	int length;
788 
789 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
790 	switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) {
791 	case GEN5_TOUCH_REPORT_ID:
792 		if (length < GEN5_TOUCH_REPORT_HEAD_SIZE ||
793 			length > GEN5_TOUCH_REPORT_MAX_SIZE)
794 			return -EINVAL;
795 		break;
796 	case GEN5_BTN_REPORT_ID:
797 	case GEN5_OLD_PUSH_BTN_REPORT_ID:
798 	case GEN5_PUSH_BTN_REPORT_ID:
799 		if (length < GEN5_BTN_REPORT_HEAD_SIZE ||
800 			length > GEN5_BTN_REPORT_MAX_SIZE)
801 			return -EINVAL;
802 		break;
803 	case GEN5_WAKEUP_EVENT_REPORT_ID:
804 		if (length != GEN5_WAKEUP_EVENT_SIZE)
805 			return -EINVAL;
806 		break;
807 	default:
808 		return -EINVAL;
809 	}
810 
811 	cyapa->gen = CYAPA_GEN5;
812 	cyapa->state = CYAPA_STATE_GEN5_APP;
813 	return 0;
814 }
815 
816 static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
817 {
818 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
819 	int length;
820 	int ret;
821 
822 	/*
823 	 * Must read report data through out,
824 	 * otherwise Gen5 trackpad cannot response next command
825 	 * or report any touch or button data.
826 	 */
827 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
828 	ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
829 	if (ret != length)
830 		return ret < 0 ? ret : -EIO;
831 
832 	if (length == GEN5_RESP_LENGTH_SIZE) {
833 		/* Previous command has read the data through out. */
834 		if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
835 				GEN5_BL_RESP_REPORT_ID) {
836 			/* Gen5 BL command response data detected */
837 			cyapa->gen = CYAPA_GEN5;
838 			cyapa->state = CYAPA_STATE_GEN5_BL;
839 		} else {
840 			/* Gen5 APP command response data detected */
841 			cyapa->gen = CYAPA_GEN5;
842 			cyapa->state = CYAPA_STATE_GEN5_APP;
843 		}
844 	} else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
845 				GEN5_BL_RESP_REPORT_ID) &&
846 			(gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
847 				GEN5_RESP_RSVD_KEY) &&
848 			(gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] ==
849 				GEN5_SOP_KEY) &&
850 			(gen5_pip->empty_buf[length - 1] ==
851 				GEN5_EOP_KEY)) {
852 		/* Gen5 BL command response data detected */
853 		cyapa->gen = CYAPA_GEN5;
854 		cyapa->state = CYAPA_STATE_GEN5_BL;
855 	} else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
856 				GEN5_APP_RESP_REPORT_ID &&
857 			gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
858 				GEN5_RESP_RSVD_KEY) {
859 		/* Gen5 APP command response data detected */
860 		cyapa->gen = CYAPA_GEN5;
861 		cyapa->state = CYAPA_STATE_GEN5_APP;
862 	} else {
863 		/* Should not happen!!! */
864 		cyapa->state = CYAPA_STATE_NO_DEVICE;
865 	}
866 
867 	return 0;
868 }
869 
870 static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
871 {
872 	int length;
873 
874 	if (!reg_data || len < 3)
875 		return -EINVAL;
876 
877 	cyapa->state = CYAPA_STATE_NO_DEVICE;
878 
879 	/* Parse based on Gen5 characteristic registers and bits */
880 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
881 	if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) {
882 		gen5_idle_state_parse(cyapa);
883 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
884 			(reg_data[2] == GEN5_BL_HID_REPORT_ID ||
885 				reg_data[2] == GEN5_APP_HID_REPORT_ID)) {
886 		gen5_hid_description_header_parse(cyapa, reg_data);
887 	} else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
888 			length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
889 			reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
890 		/* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
891 		cyapa->gen = CYAPA_GEN5;
892 		cyapa->state = CYAPA_STATE_GEN5_APP;
893 	} else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
894 			reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
895 		/* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */
896 		cyapa->gen = CYAPA_GEN5;
897 		cyapa->state = CYAPA_STATE_GEN5_BL;
898 	} else if (reg_data[2] == GEN5_TOUCH_REPORT_ID ||
899 			reg_data[2] == GEN5_BTN_REPORT_ID ||
900 			reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
901 			reg_data[2] == GEN5_PUSH_BTN_REPORT_ID ||
902 			reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) {
903 		gen5_report_data_header_parse(cyapa, reg_data);
904 	} else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID ||
905 			reg_data[2] == GEN5_APP_RESP_REPORT_ID) {
906 		gen5_cmd_resp_header_parse(cyapa, reg_data);
907 	}
908 
909 	if (cyapa->gen == CYAPA_GEN5) {
910 		/*
911 		 * Must read the content (e.g.: report description and so on)
912 		 * from trackpad device throughout. Otherwise,
913 		 * Gen5 trackpad cannot response to next command or
914 		 * report any touch or button data later.
915 		 */
916 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
917 
918 		if (cyapa->state == CYAPA_STATE_GEN5_APP ||
919 			cyapa->state == CYAPA_STATE_GEN5_BL)
920 			return 0;
921 	}
922 
923 	return -EAGAIN;
924 }
925 
926 static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
927 {
928 	if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
929 		return false;
930 
931 	if (buf[0] == 0 && buf[1] == 0)
932 		return true;
933 
934 	/* Exit bootloader failed for some reason. */
935 	if (len == GEN5_BL_FAIL_EXIT_RESP_LEN &&
936 			buf[GEN5_RESP_REPORT_ID_OFFSET] ==
937 				GEN5_BL_RESP_REPORT_ID &&
938 			buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
939 			buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY &&
940 			buf[10] == GEN5_EOP_KEY)
941 		return true;
942 
943 	return false;
944 }
945 
946 static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
947 {
948 
949 	u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
950 		0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
951 		0x20, 0xc7, 0x17
952 	};
953 	u8 resp_data[11];
954 	int resp_len;
955 	int error;
956 
957 	resp_len = sizeof(resp_data);
958 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
959 			bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
960 			resp_data, &resp_len,
961 			5000, cyapa_gen5_sort_bl_exit_data, false);
962 	if (error)
963 		return error;
964 
965 	if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN ||
966 			resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
967 				GEN5_BL_RESP_REPORT_ID)
968 		return -EAGAIN;
969 
970 	if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
971 		return 0;
972 
973 	return -ENODEV;
974 }
975 
976 static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
977 {
978 	u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
979 	u8 resp_data[6];
980 	int resp_len;
981 	int error;
982 
983 	cmd[7] = power_state;
984 	resp_len = sizeof(resp_data);
985 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
986 			resp_data, &resp_len,
987 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
988 	if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
989 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
990 		return error < 0 ? error : -EINVAL;
991 
992 	return 0;
993 }
994 
995 static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
996 		u8 parameter_id, u16 interval_time)
997 {
998 	struct gen5_app_cmd_head *app_cmd_head;
999 	struct gen5_app_set_parameter_data *parameter_data;
1000 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1001 	int cmd_len;
1002 	u8 resp_data[7];
1003 	int resp_len;
1004 	u8 parameter_size;
1005 	int error;
1006 
1007 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1008 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1009 	parameter_data = (struct gen5_app_set_parameter_data *)
1010 			 app_cmd_head->parameter_data;
1011 	cmd_len = sizeof(struct gen5_app_cmd_head) +
1012 		  sizeof(struct gen5_app_set_parameter_data);
1013 
1014 	switch (parameter_id) {
1015 	case GEN5_PARAMETER_ACT_INTERVL_ID:
1016 		parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1017 		break;
1018 	case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1019 		parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1020 		break;
1021 	case GEN5_PARAMETER_LP_INTRVL_ID:
1022 		parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1023 		break;
1024 	default:
1025 		return -EINVAL;
1026 	}
1027 
1028 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
1029 	/*
1030 	 * Don't include unused parameter value bytes and
1031 	 * 2 bytes register address.
1032 	 */
1033 	put_unaligned_le16(cmd_len - (4 - parameter_size) - 2,
1034 			   &app_cmd_head->length);
1035 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1036 	app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1037 	parameter_data->parameter_id = parameter_id;
1038 	parameter_data->parameter_size = parameter_size;
1039 	put_unaligned_le32((u32)interval_time, &parameter_data->value);
1040 	resp_len = sizeof(resp_data);
1041 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1042 			resp_data, &resp_len,
1043 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1044 	if (error || resp_data[5] != parameter_id ||
1045 		resp_data[6] != parameter_size ||
1046 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER))
1047 		return error < 0 ? error : -EINVAL;
1048 
1049 	return 0;
1050 }
1051 
1052 static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
1053 		u8 parameter_id, u16 *interval_time)
1054 {
1055 	struct gen5_app_cmd_head *app_cmd_head;
1056 	struct gen5_app_get_parameter_data *parameter_data;
1057 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1058 	int cmd_len;
1059 	u8 resp_data[11];
1060 	int resp_len;
1061 	u8 parameter_size;
1062 	u16 mask, i;
1063 	int error;
1064 
1065 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1066 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1067 	parameter_data = (struct gen5_app_get_parameter_data *)
1068 			 app_cmd_head->parameter_data;
1069 	cmd_len = sizeof(struct gen5_app_cmd_head) +
1070 		  sizeof(struct gen5_app_get_parameter_data);
1071 
1072 	*interval_time = 0;
1073 	switch (parameter_id) {
1074 	case GEN5_PARAMETER_ACT_INTERVL_ID:
1075 		parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1076 		break;
1077 	case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1078 		parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1079 		break;
1080 	case GEN5_PARAMETER_LP_INTRVL_ID:
1081 		parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1082 		break;
1083 	default:
1084 		return -EINVAL;
1085 	}
1086 
1087 	put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1088 	/* Don't include 2 bytes register address */
1089 	put_unaligned_le16(cmd_len - 2, &app_cmd_head->length);
1090 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1091 	app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER;
1092 	parameter_data->parameter_id = parameter_id;
1093 
1094 	resp_len = sizeof(resp_data);
1095 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1096 			resp_data, &resp_len,
1097 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1098 	if (error || resp_data[5] != parameter_id || resp_data[6] == 0 ||
1099 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER))
1100 		return error < 0 ? error : -EINVAL;
1101 
1102 	mask = 0;
1103 	for (i = 0; i < parameter_size; i++)
1104 		mask |= (0xff << (i * 8));
1105 	*interval_time = get_unaligned_le16(&resp_data[7]) & mask;
1106 
1107 	return 0;
1108 }
1109 
1110 static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
1111 {
1112 	struct gen5_app_cmd_head *app_cmd_head;
1113 	u8 cmd[10];
1114 	u8 resp_data[7];
1115 	int resp_len;
1116 	int error;
1117 
1118 	memset(cmd, 0, sizeof(cmd));
1119 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1120 
1121 	put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1122 	put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
1123 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1124 	app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1125 	app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
1126 	app_cmd_head->parameter_data[1] = 0x01;
1127 	app_cmd_head->parameter_data[2] = 0x01;
1128 	resp_len = sizeof(resp_data);
1129 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1130 			resp_data, &resp_len,
1131 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1132 	if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
1133 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) ||
1134 		resp_data[6] != 0x01)
1135 		return error < 0 ? error : -EINVAL;
1136 
1137 	return 0;
1138 }
1139 
1140 static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state)
1141 {
1142 	u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
1143 	u8 resp_data[5];
1144 	int resp_len;
1145 	int error;
1146 
1147 	cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK;
1148 	resp_len = sizeof(resp_data);
1149 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1150 			resp_data, &resp_len,
1151 			500, cyapa_gen5_sort_deep_sleep_data, false);
1152 	if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state))
1153 		return -EINVAL;
1154 
1155 	return 0;
1156 }
1157 
1158 static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
1159 		u8 power_mode, u16 sleep_time)
1160 {
1161 	struct device *dev = &cyapa->client->dev;
1162 	u8 power_state;
1163 	int error;
1164 
1165 	if (cyapa->state != CYAPA_STATE_GEN5_APP)
1166 		return 0;
1167 
1168 	/* Dump all the report data before do power mode commmands. */
1169 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1170 
1171 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
1172 		/*
1173 		 * Assume TP in deep sleep mode when driver is loaded,
1174 		 * avoid driver unload and reload command IO issue caused by TP
1175 		 * has been set into deep sleep mode when unloading.
1176 		 */
1177 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1178 	}
1179 
1180 	if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) &&
1181 			GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
1182 		if (cyapa_gen5_get_interval_time(cyapa,
1183 				GEN5_PARAMETER_LP_INTRVL_ID,
1184 				&cyapa->dev_sleep_time) != 0)
1185 			GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
1186 
1187 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) {
1188 		if (power_mode == PWR_MODE_OFF ||
1189 			power_mode == PWR_MODE_FULL_ACTIVE ||
1190 			power_mode == PWR_MODE_BTN_ONLY ||
1191 			GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
1192 			/* Has in correct power mode state, early return. */
1193 			return 0;
1194 		}
1195 	}
1196 
1197 	if (power_mode == PWR_MODE_OFF) {
1198 		error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF);
1199 		if (error) {
1200 			dev_err(dev, "enter deep sleep fail: %d\n", error);
1201 			return error;
1202 		}
1203 
1204 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1205 		return 0;
1206 	}
1207 
1208 	/*
1209 	 * When trackpad in power off mode, it cannot change to other power
1210 	 * state directly, must be wake up from sleep firstly, then
1211 	 * continue to do next power sate change.
1212 	 */
1213 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
1214 		error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON);
1215 		if (error) {
1216 			dev_err(dev, "deep sleep wake fail: %d\n", error);
1217 			return error;
1218 		}
1219 	}
1220 
1221 	if (power_mode == PWR_MODE_FULL_ACTIVE) {
1222 		error = cyapa_gen5_change_power_state(cyapa,
1223 				GEN5_POWER_STATE_ACTIVE);
1224 		if (error) {
1225 			dev_err(dev, "change to active fail: %d\n", error);
1226 			return error;
1227 		}
1228 
1229 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
1230 	} else if (power_mode == PWR_MODE_BTN_ONLY) {
1231 		error = cyapa_gen5_change_power_state(cyapa,
1232 				GEN5_POWER_STATE_BTN_ONLY);
1233 		if (error) {
1234 			dev_err(dev, "fail to button only mode: %d\n", error);
1235 			return error;
1236 		}
1237 
1238 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
1239 	} else {
1240 		/*
1241 		 * Continue to change power mode even failed to set
1242 		 * interval time, it won't affect the power mode change.
1243 		 * except the sleep interval time is not correct.
1244 		 */
1245 		if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) ||
1246 				sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa))
1247 			if (cyapa_gen5_set_interval_time(cyapa,
1248 					GEN5_PARAMETER_LP_INTRVL_ID,
1249 					sleep_time) == 0)
1250 				GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
1251 
1252 		if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
1253 			power_state = GEN5_POWER_STATE_READY;
1254 		else
1255 			power_state = GEN5_POWER_STATE_IDLE;
1256 		error = cyapa_gen5_change_power_state(cyapa, power_state);
1257 		if (error) {
1258 			dev_err(dev, "set power state to 0x%02x failed: %d\n",
1259 				power_state, error);
1260 			return error;
1261 		}
1262 
1263 		/*
1264 		 * Disable pip report for a little time, firmware will
1265 		 * re-enable it automatically. It's used to fix the issue
1266 		 * that trackpad unable to report signal to wake system up
1267 		 * in the special situation that system is in suspending, and
1268 		 * at the same time, user touch trackpad to wake system up.
1269 		 * This function can avoid the data to be buffured when system
1270 		 * is suspending which may cause interrput line unable to be
1271 		 * asserted again.
1272 		 */
1273 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1274 		cyapa_gen5_disable_pip_report(cyapa);
1275 
1276 		GEN5_DEV_SET_PWR_STATE(cyapa,
1277 			cyapa_sleep_time_to_pwr_cmd(sleep_time));
1278 	}
1279 
1280 	return 0;
1281 }
1282 
1283 static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
1284 		u8 *buf, int len)
1285 {
1286 	/* Check the report id and command code */
1287 	if (VALID_CMD_RESP_HEADER(buf, 0x02))
1288 		return true;
1289 
1290 	return false;
1291 }
1292 
1293 static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
1294 {
1295 	u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
1296 		0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
1297 	};
1298 	u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN];
1299 	int resp_len;
1300 	int error;
1301 
1302 	resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN;
1303 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1304 			bl_query_data_cmd, sizeof(bl_query_data_cmd),
1305 			resp_data, &resp_len,
1306 			500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false);
1307 	if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN ||
1308 		!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1309 		return error ? error : -EIO;
1310 
1311 	memcpy(&cyapa->product_id[0], &resp_data[8], 5);
1312 	cyapa->product_id[5] = '-';
1313 	memcpy(&cyapa->product_id[6], &resp_data[13], 6);
1314 	cyapa->product_id[12] = '-';
1315 	memcpy(&cyapa->product_id[13], &resp_data[19], 2);
1316 	cyapa->product_id[15] = '\0';
1317 
1318 	cyapa->fw_maj_ver = resp_data[22];
1319 	cyapa->fw_min_ver = resp_data[23];
1320 
1321 	return 0;
1322 }
1323 
1324 static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
1325 {
1326 	u8 get_system_information[] = {
1327 		0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
1328 	};
1329 	u8 resp_data[71];
1330 	int resp_len;
1331 	u16 product_family;
1332 	int error;
1333 
1334 	resp_len = sizeof(resp_data);
1335 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1336 			get_system_information, sizeof(get_system_information),
1337 			resp_data, &resp_len,
1338 			2000, cyapa_gen5_sort_system_info_data, false);
1339 	if (error || resp_len < sizeof(resp_data))
1340 		return error ? error : -EIO;
1341 
1342 	product_family = get_unaligned_le16(&resp_data[7]);
1343 	if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
1344 		GEN5_PRODUCT_FAMILY_TRACKPAD)
1345 		return -EINVAL;
1346 
1347 	cyapa->fw_maj_ver = resp_data[15];
1348 	cyapa->fw_min_ver = resp_data[16];
1349 
1350 	cyapa->electrodes_x = resp_data[52];
1351 	cyapa->electrodes_y = resp_data[53];
1352 
1353 	cyapa->physical_size_x =  get_unaligned_le16(&resp_data[54]) / 100;
1354 	cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
1355 
1356 	cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
1357 	cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
1358 
1359 	cyapa->max_z = get_unaligned_le16(&resp_data[62]);
1360 
1361 	cyapa->x_origin = resp_data[64] & 0x01;
1362 	cyapa->y_origin = resp_data[65] & 0x01;
1363 
1364 	cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
1365 
1366 	memcpy(&cyapa->product_id[0], &resp_data[33], 5);
1367 	cyapa->product_id[5] = '-';
1368 	memcpy(&cyapa->product_id[6], &resp_data[38], 6);
1369 	cyapa->product_id[12] = '-';
1370 	memcpy(&cyapa->product_id[13], &resp_data[44], 2);
1371 	cyapa->product_id[15] = '\0';
1372 
1373 	if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
1374 		!cyapa->physical_size_x || !cyapa->physical_size_y ||
1375 		!cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
1376 		return -EINVAL;
1377 
1378 	return 0;
1379 }
1380 
1381 static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
1382 {
1383 	struct device *dev = &cyapa->client->dev;
1384 	int error;
1385 
1386 	if (cyapa->gen != CYAPA_GEN5)
1387 		return -ENODEV;
1388 
1389 	switch (cyapa->state) {
1390 	case CYAPA_STATE_GEN5_BL:
1391 		error = cyapa_gen5_bl_exit(cyapa);
1392 		if (error) {
1393 			/* Rry to update trackpad product information. */
1394 			cyapa_gen5_bl_query_data(cyapa);
1395 			goto out;
1396 		}
1397 
1398 		cyapa->state = CYAPA_STATE_GEN5_APP;
1399 
1400 	case CYAPA_STATE_GEN5_APP:
1401 		/*
1402 		 * If trackpad device in deep sleep mode,
1403 		 * the app command will fail.
1404 		 * So always try to reset trackpad device to full active when
1405 		 * the device state is requeried.
1406 		 */
1407 		error = cyapa_gen5_set_power_mode(cyapa,
1408 				PWR_MODE_FULL_ACTIVE, 0);
1409 		if (error)
1410 			dev_warn(dev, "%s: failed to set power active mode.\n",
1411 				__func__);
1412 
1413 		/* Get trackpad product information. */
1414 		error = cyapa_gen5_get_query_data(cyapa);
1415 		if (error)
1416 			goto out;
1417 		/* Only support product ID starting with CYTRA */
1418 		if (memcmp(cyapa->product_id, product_id,
1419 				strlen(product_id)) != 0) {
1420 			dev_err(dev, "%s: unknown product ID (%s)\n",
1421 				__func__, cyapa->product_id);
1422 			error = -EINVAL;
1423 		}
1424 		break;
1425 	default:
1426 		error = -EINVAL;
1427 	}
1428 
1429 out:
1430 	return error;
1431 }
1432 
1433 /*
1434  * Return false, do not continue process
1435  * Return true, continue process.
1436  */
1437 static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
1438 {
1439 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
1440 	int length;
1441 
1442 	if (atomic_read(&gen5_pip->cmd_issued)) {
1443 		/* Polling command response data. */
1444 		if (gen5_pip->is_irq_mode == false)
1445 			return false;
1446 
1447 		/*
1448 		 * Read out all none command response data.
1449 		 * these output data may caused by user put finger on
1450 		 * trackpad when host waiting the command response.
1451 		 */
1452 		cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf,
1453 			GEN5_RESP_LENGTH_SIZE);
1454 		length = get_unaligned_le16(gen5_pip->irq_cmd_buf);
1455 		length = (length <= GEN5_RESP_LENGTH_SIZE) ?
1456 				GEN5_RESP_LENGTH_SIZE : length;
1457 		if (length > GEN5_RESP_LENGTH_SIZE)
1458 			cyapa_i2c_pip_read(cyapa,
1459 				gen5_pip->irq_cmd_buf, length);
1460 
1461 		if (!(gen5_pip->resp_sort_func &&
1462 			gen5_pip->resp_sort_func(cyapa,
1463 				gen5_pip->irq_cmd_buf, length))) {
1464 			/*
1465 			 * Cover the Gen5 V1 firmware issue.
1466 			 * The issue is there is no interrut will be
1467 			 * asserted to notityf host to read a command
1468 			 * data out when always has finger touch on
1469 			 * trackpad during the command is issued to
1470 			 * trackad device.
1471 			 * This issue has the scenario is that,
1472 			 * user always has his fingers touched on
1473 			 * trackpad device when booting/rebooting
1474 			 * their chrome book.
1475 			 */
1476 			length = *gen5_pip->resp_len;
1477 			cyapa_empty_pip_output_data(cyapa,
1478 					gen5_pip->resp_data,
1479 					&length,
1480 					gen5_pip->resp_sort_func);
1481 			if (gen5_pip->resp_len && length != 0) {
1482 				*gen5_pip->resp_len = length;
1483 				atomic_dec(&gen5_pip->cmd_issued);
1484 				complete(&gen5_pip->cmd_ready);
1485 			}
1486 			return false;
1487 		}
1488 
1489 		if (gen5_pip->resp_data && gen5_pip->resp_len) {
1490 			*gen5_pip->resp_len = (*gen5_pip->resp_len < length) ?
1491 				*gen5_pip->resp_len : length;
1492 			memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf,
1493 				*gen5_pip->resp_len);
1494 		}
1495 		atomic_dec(&gen5_pip->cmd_issued);
1496 		complete(&gen5_pip->cmd_ready);
1497 		return false;
1498 	}
1499 
1500 	return true;
1501 }
1502 
1503 static void cyapa_gen5_report_buttons(struct cyapa *cyapa,
1504 		const struct cyapa_gen5_report_data *report_data)
1505 {
1506 	struct input_dev *input = cyapa->input;
1507 	u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET];
1508 
1509 	buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
1510 
1511 	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
1512 		input_report_key(input, BTN_LEFT,
1513 			!!(buttons & CAPABILITY_LEFT_BTN_MASK));
1514 	}
1515 	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
1516 		input_report_key(input, BTN_MIDDLE,
1517 			!!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
1518 	}
1519 	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
1520 		input_report_key(input, BTN_RIGHT,
1521 			!!(buttons & CAPABILITY_RIGHT_BTN_MASK));
1522 	}
1523 
1524 	input_sync(input);
1525 }
1526 
1527 static void cyapa_gen5_report_slot_data(struct cyapa *cyapa,
1528 		const struct cyapa_gen5_touch_record *touch)
1529 {
1530 	struct input_dev *input = cyapa->input;
1531 	u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id);
1532 	int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id);
1533 	int x, y;
1534 
1535 	if (event_id == RECORD_EVENT_LIFTOFF)
1536 		return;
1537 
1538 	input_mt_slot(input, slot);
1539 	input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
1540 	x = (touch->x_hi << 8) | touch->x_lo;
1541 	if (cyapa->x_origin)
1542 		x = cyapa->max_abs_x - x;
1543 	input_report_abs(input, ABS_MT_POSITION_X, x);
1544 	y = (touch->y_hi << 8) | touch->y_lo;
1545 	if (cyapa->y_origin)
1546 		y = cyapa->max_abs_y - y;
1547 	input_report_abs(input, ABS_MT_POSITION_Y, y);
1548 	input_report_abs(input, ABS_MT_PRESSURE,
1549 		touch->z);
1550 	input_report_abs(input, ABS_MT_TOUCH_MAJOR,
1551 		touch->major_axis_len);
1552 	input_report_abs(input, ABS_MT_TOUCH_MINOR,
1553 		touch->minor_axis_len);
1554 
1555 	input_report_abs(input, ABS_MT_WIDTH_MAJOR,
1556 		touch->major_tool_len);
1557 	input_report_abs(input, ABS_MT_WIDTH_MINOR,
1558 		touch->minor_tool_len);
1559 
1560 	input_report_abs(input, ABS_MT_ORIENTATION,
1561 		touch->orientation);
1562 }
1563 
1564 static void cyapa_gen5_report_touches(struct cyapa *cyapa,
1565 		const struct cyapa_gen5_report_data *report_data)
1566 {
1567 	struct input_dev *input = cyapa->input;
1568 	unsigned int touch_num;
1569 	int i;
1570 
1571 	touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] &
1572 			GEN5_NUMBER_OF_TOUCH_MASK;
1573 
1574 	for (i = 0; i < touch_num; i++)
1575 		cyapa_gen5_report_slot_data(cyapa,
1576 			&report_data->touch_records[i]);
1577 
1578 	input_mt_sync_frame(input);
1579 	input_sync(input);
1580 }
1581 
1582 static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
1583 {
1584 	struct device *dev = &cyapa->client->dev;
1585 	struct cyapa_gen5_report_data report_data;
1586 	int ret;
1587 	u8 report_id;
1588 	unsigned int report_len;
1589 
1590 	if (cyapa->gen != CYAPA_GEN5 ||
1591 		cyapa->state != CYAPA_STATE_GEN5_APP) {
1592 		dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
1593 			cyapa->gen, cyapa->state);
1594 		return -EINVAL;
1595 	}
1596 
1597 	ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
1598 			GEN5_RESP_LENGTH_SIZE);
1599 	if (ret != GEN5_RESP_LENGTH_SIZE) {
1600 		dev_err(dev, "failed to read length bytes, (%d)\n", ret);
1601 		return -EINVAL;
1602 	}
1603 
1604 	report_len = get_unaligned_le16(
1605 			&report_data.report_head[GEN5_RESP_LENGTH_OFFSET]);
1606 	if (report_len < GEN5_RESP_LENGTH_SIZE) {
1607 		/* Invliad length or internal reset happened. */
1608 		dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
1609 			report_len, report_data.report_head[0],
1610 			report_data.report_head[1]);
1611 		return -EINVAL;
1612 	}
1613 
1614 	/* Idle, no data for report. */
1615 	if (report_len == GEN5_RESP_LENGTH_SIZE)
1616 		return 0;
1617 
1618 	ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
1619 	if (ret != report_len) {
1620 		dev_err(dev, "failed to read %d bytes report data, (%d)\n",
1621 			report_len, ret);
1622 		return -EINVAL;
1623 	}
1624 
1625 	report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET];
1626 	if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID &&
1627 			report_len == GEN5_WAKEUP_EVENT_SIZE) {
1628 		/*
1629 		 * Device wake event from deep sleep mode for touch.
1630 		 * This interrupt event is used to wake system up.
1631 		 */
1632 		return 0;
1633 	} else if (report_id != GEN5_TOUCH_REPORT_ID &&
1634 			report_id != GEN5_BTN_REPORT_ID &&
1635 			report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
1636 			report_id != GEN5_PUSH_BTN_REPORT_ID) {
1637 		/* Running in BL mode or unknown response data read. */
1638 		dev_err(dev, "invalid report_id=0x%02x\n", report_id);
1639 		return -EINVAL;
1640 	}
1641 
1642 	if (report_id == GEN5_TOUCH_REPORT_ID &&
1643 		(report_len < GEN5_TOUCH_REPORT_HEAD_SIZE ||
1644 			report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) {
1645 		/* Invalid report data length for finger packet. */
1646 		dev_err(dev, "invalid touch packet length=%d\n", report_len);
1647 		return 0;
1648 	}
1649 
1650 	if ((report_id == GEN5_BTN_REPORT_ID ||
1651 			report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
1652 			report_id == GEN5_PUSH_BTN_REPORT_ID) &&
1653 		(report_len < GEN5_BTN_REPORT_HEAD_SIZE ||
1654 			report_len > GEN5_BTN_REPORT_MAX_SIZE)) {
1655 		/* Invalid report data length of button packet. */
1656 		dev_err(dev, "invalid button packet length=%d\n", report_len);
1657 		return 0;
1658 	}
1659 
1660 	if (report_id == GEN5_TOUCH_REPORT_ID)
1661 		cyapa_gen5_report_touches(cyapa, &report_data);
1662 	else
1663 		cyapa_gen5_report_buttons(cyapa, &report_data);
1664 
1665 	return 0;
1666 }
1667 
1668 const struct cyapa_dev_ops cyapa_gen5_ops = {
1669 	.initialize = cyapa_gen5_initialize,
1670 
1671 	.state_parse = cyapa_gen5_state_parse,
1672 	.operational_check = cyapa_gen5_do_operational_check,
1673 
1674 	.irq_handler = cyapa_gen5_irq_handler,
1675 	.irq_cmd_handler = cyapa_gen5_irq_cmd_handler,
1676 	.sort_empty_output_data = cyapa_empty_pip_output_data,
1677 	.set_power_mode = cyapa_gen5_set_power_mode,
1678 };
1679