xref: /linux/drivers/input/mouse/cyapa_gen5.c (revision e0bf6c5ca2d3281f231c5f0c9bf145e9513644de)
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 <asm/unaligned.h>
21 #include <linux/crc-itu-t.h>
22 #include "cyapa.h"
23 
24 
25 /* Macro of Gen5 */
26 #define RECORD_EVENT_NONE        0
27 #define RECORD_EVENT_TOUCHDOWN	 1
28 #define RECORD_EVENT_DISPLACE    2
29 #define RECORD_EVENT_LIFTOFF     3
30 
31 #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE      0x80
32 #define CYAPA_TSG_IMG_FW_HDR_SIZE           13
33 #define CYAPA_TSG_FW_ROW_SIZE               (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
34 #define CYAPA_TSG_IMG_START_ROW_NUM         0x002e
35 #define CYAPA_TSG_IMG_END_ROW_NUM           0x01fe
36 #define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
37 #define CYAPA_TSG_IMG_MAX_RECORDS           (CYAPA_TSG_IMG_END_ROW_NUM - \
38 				CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
39 #define CYAPA_TSG_IMG_READ_SIZE             (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
40 #define CYAPA_TSG_START_OF_APPLICATION      0x1700
41 #define CYAPA_TSG_APP_INTEGRITY_SIZE        60
42 #define CYAPA_TSG_FLASH_MAP_METADATA_SIZE   60
43 #define CYAPA_TSG_BL_KEY_SIZE               8
44 
45 #define CYAPA_TSG_MAX_CMD_SIZE              256
46 
47 #define GEN5_BL_CMD_VERIFY_APP_INTEGRITY    0x31
48 #define GEN5_BL_CMD_GET_BL_INFO		    0x38
49 #define GEN5_BL_CMD_PROGRAM_VERIFY_ROW      0x39
50 #define GEN5_BL_CMD_LAUNCH_APP		    0x3b
51 #define GEN5_BL_CMD_INITIATE_BL		    0x48
52 
53 #define GEN5_HID_DESCRIPTOR_ADDR	0x0001
54 #define GEN5_REPORT_DESCRIPTOR_ADDR	0x0002
55 #define GEN5_INPUT_REPORT_ADDR		0x0003
56 #define GEN5_OUTPUT_REPORT_ADDR		0x0004
57 #define GEN5_CMD_DATA_ADDR		0x0006
58 
59 #define GEN5_TOUCH_REPORT_HEAD_SIZE     7
60 #define GEN5_TOUCH_REPORT_MAX_SIZE      127
61 #define GEN5_BTN_REPORT_HEAD_SIZE       6
62 #define GEN5_BTN_REPORT_MAX_SIZE        14
63 #define GEN5_WAKEUP_EVENT_SIZE          4
64 #define GEN5_RAW_DATA_HEAD_SIZE         24
65 
66 #define GEN5_BL_CMD_REPORT_ID           0x40
67 #define GEN5_BL_RESP_REPORT_ID          0x30
68 #define GEN5_APP_CMD_REPORT_ID          0x2f
69 #define GEN5_APP_RESP_REPORT_ID         0x1f
70 
71 #define GEN5_APP_DEEP_SLEEP_REPORT_ID   0xf0
72 #define GEN5_DEEP_SLEEP_RESP_LENGTH     5
73 
74 #define GEN5_CMD_GET_PARAMETER		     0x05
75 #define GEN5_CMD_SET_PARAMETER		     0x06
76 #define GEN5_PARAMETER_ACT_INTERVL_ID        0x4d
77 #define GEN5_PARAMETER_ACT_INTERVL_SIZE      1
78 #define GEN5_PARAMETER_ACT_LFT_INTERVL_ID    0x4f
79 #define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE  2
80 #define GEN5_PARAMETER_LP_INTRVL_ID          0x4c
81 #define GEN5_PARAMETER_LP_INTRVL_SIZE        2
82 
83 #define GEN5_PARAMETER_DISABLE_PIP_REPORT    0x08
84 
85 #define GEN5_POWER_STATE_ACTIVE              0x01
86 #define GEN5_POWER_STATE_LOOK_FOR_TOUCH      0x02
87 #define GEN5_POWER_STATE_READY               0x03
88 #define GEN5_POWER_STATE_IDLE                0x04
89 #define GEN5_POWER_STATE_BTN_ONLY            0x05
90 #define GEN5_POWER_STATE_OFF                 0x06
91 
92 #define GEN5_DEEP_SLEEP_STATE_MASK  0x03
93 #define GEN5_DEEP_SLEEP_STATE_ON    0x00
94 #define GEN5_DEEP_SLEEP_STATE_OFF   0x01
95 
96 #define GEN5_DEEP_SLEEP_OPCODE      0x08
97 #define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
98 
99 #define GEN5_POWER_READY_MAX_INTRVL_TIME  50   /* Unit: ms */
100 #define GEN5_POWER_IDLE_MAX_INTRVL_TIME   250  /* Unit: ms */
101 
102 #define GEN5_CMD_REPORT_ID_OFFSET       4
103 
104 #define GEN5_RESP_REPORT_ID_OFFSET      2
105 #define GEN5_RESP_RSVD_OFFSET           3
106 #define     GEN5_RESP_RSVD_KEY          0x00
107 #define GEN5_RESP_BL_SOP_OFFSET         4
108 #define     GEN5_SOP_KEY                0x01  /* Start of Packet */
109 #define     GEN5_EOP_KEY                0x17  /* End of Packet */
110 #define GEN5_RESP_APP_CMD_OFFSET        4
111 #define     GET_GEN5_CMD_CODE(reg)      ((reg) & 0x7f)
112 
113 #define VALID_CMD_RESP_HEADER(resp, cmd)				    \
114 	(((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \
115 	((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) &&	    \
116 	(GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd)))
117 
118 #define GEN5_MIN_BL_CMD_LENGTH           13
119 #define GEN5_MIN_BL_RESP_LENGTH          11
120 #define GEN5_MIN_APP_CMD_LENGTH          7
121 #define GEN5_MIN_APP_RESP_LENGTH         5
122 #define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6
123 
124 #define GEN5_RESP_LENGTH_OFFSET  0x00
125 #define GEN5_RESP_LENGTH_SIZE    2
126 
127 #define GEN5_HID_DESCRIPTOR_SIZE      32
128 #define GEN5_BL_HID_REPORT_ID         0xff
129 #define GEN5_APP_HID_REPORT_ID        0xf7
130 #define GEN5_BL_MAX_OUTPUT_LENGTH     0x0100
131 #define GEN5_APP_MAX_OUTPUT_LENGTH    0x00fe
132 
133 #define GEN5_BL_REPORT_DESCRIPTOR_SIZE            0x1d
134 #define GEN5_BL_REPORT_DESCRIPTOR_ID              0xfe
135 #define GEN5_APP_REPORT_DESCRIPTOR_SIZE           0xee
136 #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE  0xfa
137 #define GEN5_APP_REPORT_DESCRIPTOR_ID             0xf6
138 
139 #define GEN5_TOUCH_REPORT_ID         0x01
140 #define GEN5_BTN_REPORT_ID           0x03
141 #define GEN5_WAKEUP_EVENT_REPORT_ID  0x04
142 #define GEN5_OLD_PUSH_BTN_REPORT_ID  0x05
143 #define GEN5_PUSH_BTN_REPORT_ID      0x06
144 
145 #define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
146 
147 #define GEN5_BL_INITIATE_RESP_LEN            11
148 #define GEN5_BL_FAIL_EXIT_RESP_LEN           11
149 #define GEN5_BL_FAIL_EXIT_STATUS_CODE        0x0c
150 #define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN    12
151 #define GEN5_BL_INTEGRITY_CHEKC_PASS         0x00
152 #define GEN5_BL_BLOCK_WRITE_RESP_LEN         11
153 #define GEN5_BL_READ_APP_INFO_RESP_LEN       31
154 #define GEN5_CMD_CALIBRATE                   0x28
155 #define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE   0x00
156 #define CYAPA_SENSING_MODE_SELF_CAP          0x02
157 
158 #define GEN5_CMD_RETRIEVE_DATA_STRUCTURE     0x24
159 #define GEN5_RETRIEVE_MUTUAL_PWC_DATA        0x00
160 #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA      0x01
161 
162 #define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
163 
164 #define GEN5_CMD_EXECUTE_PANEL_SCAN          0x2a
165 #define GEN5_CMD_RETRIEVE_PANEL_SCAN         0x2b
166 #define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA      0x00
167 #define GEN5_PANEL_SCAN_MUTUAL_BASELINE      0x01
168 #define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT     0x02
169 #define GEN5_PANEL_SCAN_SELF_RAW_DATA        0x03
170 #define GEN5_PANEL_SCAN_SELF_BASELINE        0x04
171 #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT       0x05
172 
173 /* The offset only valid for reterive PWC and panel scan commands */
174 #define GEN5_RESP_DATA_STRUCTURE_OFFSET      10
175 #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK      0x07
176 
177 #define	GEN5_NUMBER_OF_TOUCH_OFFSET  5
178 #define GEN5_NUMBER_OF_TOUCH_MASK    0x1f
179 #define GEN5_BUTTONS_OFFSET          5
180 #define GEN5_BUTTONS_MASK            0x0f
181 #define GEN5_GET_EVENT_ID(reg)       (((reg) >> 5) & 0x03)
182 #define GEN5_GET_TOUCH_ID(reg)       ((reg) & 0x1f)
183 
184 #define GEN5_PRODUCT_FAMILY_MASK        0xf000
185 #define GEN5_PRODUCT_FAMILY_TRACKPAD    0x1000
186 
187 #define TSG_INVALID_CMD   0xff
188 
189 struct cyapa_gen5_touch_record {
190 	/*
191 	 * Bit 7 - 3: reserved
192 	 * Bit 2 - 0: touch type;
193 	 *            0 : standard finger;
194 	 *            1 - 15 : reserved.
195 	 */
196 	u8 touch_type;
197 
198 	/*
199 	 * Bit 7: indicates touch liftoff status.
200 	 *		0 : touch is currently on the panel.
201 	 *		1 : touch record indicates a liftoff.
202 	 * Bit 6 - 5: indicates an event associated with this touch instance
203 	 *		0 : no event
204 	 *		1 : touchdown
205 	 *		2 : significant displacement (> active distance)
206 	 *		3 : liftoff (record reports last known coordinates)
207 	 * Bit 4 - 0: An arbitrary ID tag associated with a finger
208 	 *		to allow tracking a touch as it moves around the panel.
209 	 */
210 	u8 touch_tip_event_id;
211 
212 	/* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
213 	u8 x_lo;
214 
215 	/* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
216 	u8 x_hi;
217 
218 	/* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
219 	u8 y_lo;
220 
221 	/* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
222 	u8 y_hi;
223 
224 	/* Touch intensity in counts, pressure value. */
225 	u8 z;
226 
227 	/*
228 	 * The length of the major axis of the ellipse of contact between
229 	 * the finger and the panel (ABS_MT_TOUCH_MAJOR).
230 	 */
231 	u8 major_axis_len;
232 
233 	/*
234 	 * The length of the minor axis of the ellipse of contact between
235 	 * the finger and the panel (ABS_MT_TOUCH_MINOR).
236 	 */
237 	u8 minor_axis_len;
238 
239 	/*
240 	 * The length of the major axis of the approaching tool.
241 	 * (ABS_MT_WIDTH_MAJOR)
242 	 */
243 	u8 major_tool_len;
244 
245 	/*
246 	 * The length of the minor axis of the approaching tool.
247 	 * (ABS_MT_WIDTH_MINOR)
248 	 */
249 	u8 minor_tool_len;
250 
251 	/*
252 	 * The angle between the panel vertical axis and
253 	 * the major axis of the contact ellipse. This value is an 8-bit
254 	 * signed integer. The range is -127 to +127 (corresponding to
255 	 * -90 degree and +90 degree respectively).
256 	 * The positive direction is clockwise from the vertical axis.
257 	 * If the ellipse of contact degenerates into a circle,
258 	 * orientation is reported as 0.
259 	 */
260 	u8 orientation;
261 } __packed;
262 
263 struct cyapa_gen5_report_data {
264 	u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE];
265 	struct cyapa_gen5_touch_record touch_records[10];
266 } __packed;
267 
268 struct cyapa_tsg_bin_image_head {
269 	u8 head_size;  /* Unit: bytes, including itself. */
270 	u8 ttda_driver_major_version;  /* Reserved as 0. */
271 	u8 ttda_driver_minor_version;  /* Reserved as 0. */
272 	u8 fw_major_version;
273 	u8 fw_minor_version;
274 	u8 fw_revision_control_number[8];
275 } __packed;
276 
277 struct cyapa_tsg_bin_image_data_record {
278 	u8 flash_array_id;
279 	__be16 row_number;
280 	/* The number of bytes of flash data contained in this record. */
281 	__be16 record_len;
282 	/* The flash program data. */
283 	u8 record_data[CYAPA_TSG_FW_ROW_SIZE];
284 } __packed;
285 
286 struct cyapa_tsg_bin_image {
287 	struct cyapa_tsg_bin_image_head image_head;
288 	struct cyapa_tsg_bin_image_data_record records[0];
289 } __packed;
290 
291 struct gen5_bl_packet_start {
292 	u8 sop;  /* Start of packet, must be 01h */
293 	u8 cmd_code;
294 	__le16 data_length;  /* Size of data parameter start from data[0] */
295 } __packed;
296 
297 struct gen5_bl_packet_end {
298 	__le16 crc;
299 	u8 eop;  /* End of packet, must be 17h */
300 } __packed;
301 
302 struct gen5_bl_cmd_head {
303 	__le16 addr;   /* Output report register address, must be 0004h */
304 	/* Size of packet not including output report register address */
305 	__le16 length;
306 	u8 report_id;  /* Bootloader output report id, must be 40h */
307 	u8 rsvd;  /* Reserved, must be 0 */
308 	struct gen5_bl_packet_start packet_start;
309 	u8 data[0];  /* Command data variable based on commands */
310 } __packed;
311 
312 /* Initiate bootload command data structure. */
313 struct gen5_bl_initiate_cmd_data {
314 	/* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */
315 	u8 key[CYAPA_TSG_BL_KEY_SIZE];
316 	u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE];
317 	__le16 metadata_crc;
318 } __packed;
319 
320 struct gen5_bl_metadata_row_params {
321 	__le16 size;
322 	__le16 maximum_size;
323 	__le32 app_start;
324 	__le16 app_len;
325 	__le16 app_crc;
326 	__le32 app_entry;
327 	__le32 upgrade_start;
328 	__le16 upgrade_len;
329 	__le16 entry_row_crc;
330 	u8 padding[36];  /* Padding data must be 0 */
331 	__le16 metadata_crc;  /* CRC starts at offset of 60 */
332 } __packed;
333 
334 /* Bootload program and verify row command data structure */
335 struct gen5_bl_flash_row_head {
336 	u8 flash_array_id;
337 	__le16 flash_row_id;
338 	u8 flash_data[0];
339 } __packed;
340 
341 struct gen5_app_cmd_head {
342 	__le16 addr;   /* Output report register address, must be 0004h */
343 	/* Size of packet not including output report register address */
344 	__le16 length;
345 	u8 report_id;  /* Application output report id, must be 2Fh */
346 	u8 rsvd;  /* Reserved, must be 0 */
347 	/*
348 	 * Bit 7: reserved, must be 0.
349 	 * Bit 6-0: command code.
350 	 */
351 	u8 cmd_code;
352 	u8 parameter_data[0];  /* Parameter data variable based on cmd_code */
353 } __packed;
354 
355 /* Applicaton get/set parameter command data structure */
356 struct gen5_app_set_parameter_data {
357 	u8 parameter_id;
358 	u8 parameter_size;
359 	__le32 value;
360 } __packed;
361 
362 struct gen5_app_get_parameter_data {
363 	u8 parameter_id;
364 } __packed;
365 
366 struct gen5_retrieve_panel_scan_data {
367 	__le16 read_offset;
368 	__le16 read_elements;
369 	u8 data_id;
370 } __packed;
371 
372 /* Variables to record latest gen5 trackpad power states. */
373 #define GEN5_DEV_SET_PWR_STATE(cyapa, s)	((cyapa)->dev_pwr_mode = (s))
374 #define GEN5_DEV_GET_PWR_STATE(cyapa)		((cyapa)->dev_pwr_mode)
375 #define GEN5_DEV_SET_SLEEP_TIME(cyapa, t)	((cyapa)->dev_sleep_time = (t))
376 #define GEN5_DEV_GET_SLEEP_TIME(cyapa)		((cyapa)->dev_sleep_time)
377 #define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa)	\
378 		(((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME)
379 
380 
381 static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
382 	0xff, 0xfe, 0xfd, 0x5a };
383 
384 static int cyapa_gen5_initialize(struct cyapa *cyapa)
385 {
386 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
387 
388 	init_completion(&gen5_pip->cmd_ready);
389 	atomic_set(&gen5_pip->cmd_issued, 0);
390 	mutex_init(&gen5_pip->cmd_lock);
391 
392 	gen5_pip->resp_sort_func = NULL;
393 	gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
394 	gen5_pip->resp_data = NULL;
395 	gen5_pip->resp_len = NULL;
396 
397 	cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
398 	cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
399 
400 	return 0;
401 }
402 
403 /* Return negative errno, or else the number of bytes read. */
404 static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
405 {
406 	int ret;
407 
408 	if (size == 0)
409 		return 0;
410 
411 	if (!buf || size > CYAPA_REG_MAP_SIZE)
412 		return -EINVAL;
413 
414 	ret = i2c_master_recv(cyapa->client, buf, size);
415 
416 	if (ret != size)
417 		return (ret < 0) ? ret : -EIO;
418 
419 	return size;
420 }
421 
422 /**
423  * Return a negative errno code else zero on success.
424  */
425 static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
426 {
427 	int ret;
428 
429 	if (!buf || !size)
430 		return -EINVAL;
431 
432 	ret = i2c_master_send(cyapa->client, buf, size);
433 
434 	if (ret != size)
435 		return (ret < 0) ? ret : -EIO;
436 
437 	return 0;
438 }
439 
440 /**
441  * This function is aimed to dump all not read data in Gen5 trackpad
442  * before send any command, otherwise, the interrupt line will be blocked.
443  */
444 static int cyapa_empty_pip_output_data(struct cyapa *cyapa,
445 		u8 *buf, int *len, cb_sort func)
446 {
447 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
448 	int length;
449 	int report_count;
450 	int empty_count;
451 	int buf_len;
452 	int error;
453 
454 	buf_len = 0;
455 	if (len) {
456 		buf_len = (*len < CYAPA_REG_MAP_SIZE) ?
457 				*len : CYAPA_REG_MAP_SIZE;
458 		*len = 0;
459 	}
460 
461 	report_count = 8;  /* max 7 pending data before command response data */
462 	empty_count = 0;
463 	do {
464 		/*
465 		 * Depending on testing in cyapa driver, there are max 5 "02 00"
466 		 * packets between two valid buffered data report in firmware.
467 		 * So in order to dump all buffered data out and
468 		 * make interrupt line release for reassert again,
469 		 * we must set the empty_count check value bigger than 5 to
470 		 * make it work. Otherwise, in some situation,
471 		 * the interrupt line may unable to reactive again,
472 		 * which will cause trackpad device unable to
473 		 * report data any more.
474 		 * for example, it may happen in EFT and ESD testing.
475 		 */
476 		if (empty_count > 5)
477 			return 0;
478 
479 		error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf,
480 				GEN5_RESP_LENGTH_SIZE);
481 		if (error < 0)
482 			return error;
483 
484 		length = get_unaligned_le16(gen5_pip->empty_buf);
485 		if (length == GEN5_RESP_LENGTH_SIZE) {
486 			empty_count++;
487 			continue;
488 		} else if (length > CYAPA_REG_MAP_SIZE) {
489 			/* Should not happen */
490 			return -EINVAL;
491 		} else if (length == 0) {
492 			/* Application or bootloader launch data polled out. */
493 			length = GEN5_RESP_LENGTH_SIZE;
494 			if (buf && buf_len && func &&
495 				func(cyapa, gen5_pip->empty_buf, length)) {
496 				length = min(buf_len, length);
497 				memcpy(buf, gen5_pip->empty_buf, length);
498 				*len = length;
499 				/* Response found, success. */
500 				return 0;
501 			}
502 			continue;
503 		}
504 
505 		error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
506 		if (error < 0)
507 			return error;
508 
509 		report_count--;
510 		empty_count = 0;
511 		length = get_unaligned_le16(gen5_pip->empty_buf);
512 		if (length <= GEN5_RESP_LENGTH_SIZE) {
513 			empty_count++;
514 		} else if (buf && buf_len && func &&
515 			func(cyapa, gen5_pip->empty_buf, length)) {
516 			length = min(buf_len, length);
517 			memcpy(buf, gen5_pip->empty_buf, length);
518 			*len = length;
519 			/* Response found, success. */
520 			return 0;
521 		}
522 
523 		error = -EINVAL;
524 	} while (report_count);
525 
526 	return error;
527 }
528 
529 static int cyapa_do_i2c_pip_cmd_irq_sync(
530 		struct cyapa *cyapa,
531 		u8 *cmd, size_t cmd_len,
532 		unsigned long timeout)
533 {
534 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
535 	int error;
536 
537 	/* Wait for interrupt to set ready completion */
538 	init_completion(&gen5_pip->cmd_ready);
539 
540 	atomic_inc(&gen5_pip->cmd_issued);
541 	error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
542 	if (error) {
543 		atomic_dec(&gen5_pip->cmd_issued);
544 		return (error < 0) ? error : -EIO;
545 	}
546 
547 	/* Wait for interrupt to indicate command is completed. */
548 	timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready,
549 				msecs_to_jiffies(timeout));
550 	if (timeout == 0) {
551 		atomic_dec(&gen5_pip->cmd_issued);
552 		return -ETIMEDOUT;
553 	}
554 
555 	return 0;
556 }
557 
558 static int cyapa_do_i2c_pip_cmd_polling(
559 		struct cyapa *cyapa,
560 		u8 *cmd, size_t cmd_len,
561 		u8 *resp_data, int *resp_len,
562 		unsigned long timeout,
563 		cb_sort func)
564 {
565 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
566 	int tries;
567 	int length;
568 	int error;
569 
570 	atomic_inc(&gen5_pip->cmd_issued);
571 	error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
572 	if (error) {
573 		atomic_dec(&gen5_pip->cmd_issued);
574 		return error < 0 ? error : -EIO;
575 	}
576 
577 	length = resp_len ? *resp_len : 0;
578 	if (resp_data && resp_len && length != 0 && func) {
579 		tries = timeout / 5;
580 		do {
581 			usleep_range(3000, 5000);
582 			*resp_len = length;
583 			error = cyapa_empty_pip_output_data(cyapa,
584 					resp_data, resp_len, func);
585 			if (error || *resp_len == 0)
586 				continue;
587 			else
588 				break;
589 		} while (--tries > 0);
590 		if ((error || *resp_len == 0) || tries <= 0)
591 			error = error ? error : -ETIMEDOUT;
592 	}
593 
594 	atomic_dec(&gen5_pip->cmd_issued);
595 	return error;
596 }
597 
598 static int cyapa_i2c_pip_cmd_irq_sync(
599 		struct cyapa *cyapa,
600 		u8 *cmd, int cmd_len,
601 		u8 *resp_data, int *resp_len,
602 		unsigned long timeout,
603 		cb_sort func,
604 		bool irq_mode)
605 {
606 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
607 	int error;
608 
609 	if (!cmd || !cmd_len)
610 		return -EINVAL;
611 
612 	/* Commands must be serialized. */
613 	error = mutex_lock_interruptible(&gen5_pip->cmd_lock);
614 	if (error)
615 		return error;
616 
617 	gen5_pip->resp_sort_func = func;
618 	gen5_pip->resp_data = resp_data;
619 	gen5_pip->resp_len = resp_len;
620 
621 	if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH &&
622 			cmd[4] == GEN5_APP_CMD_REPORT_ID) {
623 		/* Application command */
624 		gen5_pip->in_progress_cmd = cmd[6] & 0x7f;
625 	} else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH &&
626 			cmd[4] == GEN5_BL_CMD_REPORT_ID) {
627 		/* Bootloader command */
628 		gen5_pip->in_progress_cmd = cmd[7];
629 	}
630 
631 	/* Send command data, wait and read output response data's length. */
632 	if (irq_mode) {
633 		gen5_pip->is_irq_mode = true;
634 		error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
635 							timeout);
636 		if (error == -ETIMEDOUT && resp_data &&
637 				resp_len && *resp_len != 0 && func) {
638 			/*
639 			 * For some old version, there was no interrupt for
640 			 * the command response data, so need to poll here
641 			 * to try to get the response data.
642 			 */
643 			error = cyapa_empty_pip_output_data(cyapa,
644 					resp_data, resp_len, func);
645 			if (error || *resp_len == 0)
646 				error = error ? error : -ETIMEDOUT;
647 		}
648 	} else {
649 		gen5_pip->is_irq_mode = false;
650 		error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
651 				resp_data, resp_len, timeout, func);
652 	}
653 
654 	gen5_pip->resp_sort_func = NULL;
655 	gen5_pip->resp_data = NULL;
656 	gen5_pip->resp_len = NULL;
657 	gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
658 
659 	mutex_unlock(&gen5_pip->cmd_lock);
660 	return error;
661 }
662 
663 static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
664 		u8 *data, int len)
665 {
666 	if (!data || len < GEN5_MIN_BL_RESP_LENGTH)
667 		return false;
668 
669 	/* Bootloader input report id 30h */
670 	if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID &&
671 			data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
672 			data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY)
673 		return true;
674 
675 	return false;
676 }
677 
678 static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
679 		u8 *data, int len)
680 {
681 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
682 	int resp_len;
683 
684 	if (!data || len < GEN5_MIN_APP_RESP_LENGTH)
685 		return false;
686 
687 	if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID &&
688 			data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) {
689 		resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]);
690 		if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 &&
691 			resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH &&
692 			data[5] == gen5_pip->in_progress_cmd) {
693 			/* Unsupported command code */
694 			return false;
695 		} else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) ==
696 				gen5_pip->in_progress_cmd) {
697 			/* Correct command response received */
698 			return true;
699 		}
700 	}
701 
702 	return false;
703 }
704 
705 static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa,
706 		u8 *buf, int len)
707 {
708 	if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
709 		return false;
710 
711 	/*
712 	 * After reset or power on, trackpad device always sets to 0x00 0x00
713 	 * to indicate a reset or power on event.
714 	 */
715 	if (buf[0] == 0 && buf[1] == 0)
716 		return true;
717 
718 	return false;
719 }
720 
721 static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa,
722 		u8 *buf, int len)
723 {
724 	int resp_len;
725 	int max_output_len;
726 
727 	/* Check hid descriptor. */
728 	if (len != GEN5_HID_DESCRIPTOR_SIZE)
729 		return false;
730 
731 	resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]);
732 	max_output_len = get_unaligned_le16(&buf[16]);
733 	if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) {
734 		if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID &&
735 				max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
736 			/* BL mode HID Descriptor */
737 			return true;
738 		} else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] ==
739 				GEN5_APP_HID_REPORT_ID) &&
740 				max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
741 			/* APP mode HID Descriptor */
742 			return true;
743 		}
744 	}
745 
746 	return false;
747 }
748 
749 static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa,
750 		u8 *buf, int len)
751 {
752 	if (len == GEN5_DEEP_SLEEP_RESP_LENGTH &&
753 		buf[GEN5_RESP_REPORT_ID_OFFSET] ==
754 			GEN5_APP_DEEP_SLEEP_REPORT_ID &&
755 		(buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) ==
756 			GEN5_DEEP_SLEEP_OPCODE)
757 		return true;
758 	return false;
759 }
760 
761 static int gen5_idle_state_parse(struct cyapa *cyapa)
762 {
763 	u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE];
764 	int max_output_len;
765 	int length;
766 	u8 cmd[2];
767 	int ret;
768 	int error;
769 
770 	/*
771 	 * Dump all buffered data firstly for the situation
772 	 * when the trackpad is just power on the cyapa go here.
773 	 */
774 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
775 
776 	memset(resp_data, 0, sizeof(resp_data));
777 	ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
778 	if (ret != 3)
779 		return ret < 0 ? ret : -EIO;
780 
781 	length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
782 	if (length == GEN5_RESP_LENGTH_SIZE) {
783 		/* Normal state of Gen5 with no data to respose */
784 		cyapa->gen = CYAPA_GEN5;
785 
786 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
787 
788 		/* Read description from trackpad device */
789 		cmd[0] = 0x01;
790 		cmd[1] = 0x00;
791 		length = GEN5_HID_DESCRIPTOR_SIZE;
792 		error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
793 				cmd, GEN5_RESP_LENGTH_SIZE,
794 				resp_data, &length,
795 				300,
796 				cyapa_gen5_sort_hid_descriptor_data,
797 				false);
798 		if (error)
799 			return error;
800 
801 		length = get_unaligned_le16(
802 				&resp_data[GEN5_RESP_LENGTH_OFFSET]);
803 		max_output_len = get_unaligned_le16(&resp_data[16]);
804 		if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
805 				length == GEN5_RESP_LENGTH_SIZE) &&
806 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
807 				GEN5_BL_HID_REPORT_ID) &&
808 			max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
809 			/* BL mode HID Description read */
810 			cyapa->state = CYAPA_STATE_GEN5_BL;
811 		} else if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
812 				length == GEN5_RESP_LENGTH_SIZE) &&
813 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
814 				GEN5_APP_HID_REPORT_ID) &&
815 			max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
816 			/* APP mode HID Description read */
817 			cyapa->state = CYAPA_STATE_GEN5_APP;
818 		} else {
819 			/* Should not happen!!! */
820 			cyapa->state = CYAPA_STATE_NO_DEVICE;
821 		}
822 	}
823 
824 	return 0;
825 }
826 
827 static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
828 {
829 	int length;
830 	u8 resp_data[32];
831 	int max_output_len;
832 	int ret;
833 
834 	/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
835 	 * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
836 	 *
837 	 * Must read HID Description content through out,
838 	 * otherwise Gen5 trackpad cannot response next command
839 	 * or report any touch or button data.
840 	 */
841 	ret = cyapa_i2c_pip_read(cyapa, resp_data,
842 			GEN5_HID_DESCRIPTOR_SIZE);
843 	if (ret != GEN5_HID_DESCRIPTOR_SIZE)
844 		return ret < 0 ? ret : -EIO;
845 	length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
846 	max_output_len = get_unaligned_le16(&resp_data[16]);
847 	if (length == GEN5_RESP_LENGTH_SIZE) {
848 		if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
849 				GEN5_BL_HID_REPORT_ID) {
850 			/*
851 			 * BL mode HID Description has been previously
852 			 * read out.
853 			 */
854 			cyapa->gen = CYAPA_GEN5;
855 			cyapa->state = CYAPA_STATE_GEN5_BL;
856 		} else {
857 			/*
858 			 * APP mode HID Description has been previously
859 			 * read out.
860 			 */
861 			cyapa->gen = CYAPA_GEN5;
862 			cyapa->state = CYAPA_STATE_GEN5_APP;
863 		}
864 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
865 			resp_data[2] == GEN5_BL_HID_REPORT_ID &&
866 			max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
867 		/* BL mode HID Description read. */
868 		cyapa->gen = CYAPA_GEN5;
869 		cyapa->state = CYAPA_STATE_GEN5_BL;
870 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
871 			(resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
872 				GEN5_APP_HID_REPORT_ID) &&
873 			max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
874 		/* APP mode HID Description read. */
875 		cyapa->gen = CYAPA_GEN5;
876 		cyapa->state = CYAPA_STATE_GEN5_APP;
877 	} else {
878 		/* Should not happen!!! */
879 		cyapa->state = CYAPA_STATE_NO_DEVICE;
880 	}
881 
882 	return 0;
883 }
884 
885 static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
886 {
887 	int length;
888 
889 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
890 	switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) {
891 	case GEN5_TOUCH_REPORT_ID:
892 		if (length < GEN5_TOUCH_REPORT_HEAD_SIZE ||
893 			length > GEN5_TOUCH_REPORT_MAX_SIZE)
894 			return -EINVAL;
895 		break;
896 	case GEN5_BTN_REPORT_ID:
897 	case GEN5_OLD_PUSH_BTN_REPORT_ID:
898 	case GEN5_PUSH_BTN_REPORT_ID:
899 		if (length < GEN5_BTN_REPORT_HEAD_SIZE ||
900 			length > GEN5_BTN_REPORT_MAX_SIZE)
901 			return -EINVAL;
902 		break;
903 	case GEN5_WAKEUP_EVENT_REPORT_ID:
904 		if (length != GEN5_WAKEUP_EVENT_SIZE)
905 			return -EINVAL;
906 		break;
907 	default:
908 		return -EINVAL;
909 	}
910 
911 	cyapa->gen = CYAPA_GEN5;
912 	cyapa->state = CYAPA_STATE_GEN5_APP;
913 	return 0;
914 }
915 
916 static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
917 {
918 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
919 	int length;
920 	int ret;
921 
922 	/*
923 	 * Must read report data through out,
924 	 * otherwise Gen5 trackpad cannot response next command
925 	 * or report any touch or button data.
926 	 */
927 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
928 	ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
929 	if (ret != length)
930 		return ret < 0 ? ret : -EIO;
931 
932 	if (length == GEN5_RESP_LENGTH_SIZE) {
933 		/* Previous command has read the data through out. */
934 		if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
935 				GEN5_BL_RESP_REPORT_ID) {
936 			/* Gen5 BL command response data detected */
937 			cyapa->gen = CYAPA_GEN5;
938 			cyapa->state = CYAPA_STATE_GEN5_BL;
939 		} else {
940 			/* Gen5 APP command response data detected */
941 			cyapa->gen = CYAPA_GEN5;
942 			cyapa->state = CYAPA_STATE_GEN5_APP;
943 		}
944 	} else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
945 				GEN5_BL_RESP_REPORT_ID) &&
946 			(gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
947 				GEN5_RESP_RSVD_KEY) &&
948 			(gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] ==
949 				GEN5_SOP_KEY) &&
950 			(gen5_pip->empty_buf[length - 1] ==
951 				GEN5_EOP_KEY)) {
952 		/* Gen5 BL command response data detected */
953 		cyapa->gen = CYAPA_GEN5;
954 		cyapa->state = CYAPA_STATE_GEN5_BL;
955 	} else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
956 				GEN5_APP_RESP_REPORT_ID &&
957 			gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
958 				GEN5_RESP_RSVD_KEY) {
959 		/* Gen5 APP command response data detected */
960 		cyapa->gen = CYAPA_GEN5;
961 		cyapa->state = CYAPA_STATE_GEN5_APP;
962 	} else {
963 		/* Should not happen!!! */
964 		cyapa->state = CYAPA_STATE_NO_DEVICE;
965 	}
966 
967 	return 0;
968 }
969 
970 static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
971 {
972 	int length;
973 
974 	if (!reg_data || len < 3)
975 		return -EINVAL;
976 
977 	cyapa->state = CYAPA_STATE_NO_DEVICE;
978 
979 	/* Parse based on Gen5 characteristic registers and bits */
980 	length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
981 	if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) {
982 		gen5_idle_state_parse(cyapa);
983 	} else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
984 			(reg_data[2] == GEN5_BL_HID_REPORT_ID ||
985 				reg_data[2] == GEN5_APP_HID_REPORT_ID)) {
986 		gen5_hid_description_header_parse(cyapa, reg_data);
987 	} else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
988 			length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
989 			reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
990 		/* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
991 		cyapa->gen = CYAPA_GEN5;
992 		cyapa->state = CYAPA_STATE_GEN5_APP;
993 	} else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
994 			reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
995 		/* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */
996 		cyapa->gen = CYAPA_GEN5;
997 		cyapa->state = CYAPA_STATE_GEN5_BL;
998 	} else if (reg_data[2] == GEN5_TOUCH_REPORT_ID ||
999 			reg_data[2] == GEN5_BTN_REPORT_ID ||
1000 			reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
1001 			reg_data[2] == GEN5_PUSH_BTN_REPORT_ID ||
1002 			reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) {
1003 		gen5_report_data_header_parse(cyapa, reg_data);
1004 	} else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID ||
1005 			reg_data[2] == GEN5_APP_RESP_REPORT_ID) {
1006 		gen5_cmd_resp_header_parse(cyapa, reg_data);
1007 	}
1008 
1009 	if (cyapa->gen == CYAPA_GEN5) {
1010 		/*
1011 		 * Must read the content (e.g.: report description and so on)
1012 		 * from trackpad device throughout. Otherwise,
1013 		 * Gen5 trackpad cannot response to next command or
1014 		 * report any touch or button data later.
1015 		 */
1016 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1017 
1018 		if (cyapa->state == CYAPA_STATE_GEN5_APP ||
1019 			cyapa->state == CYAPA_STATE_GEN5_BL)
1020 			return 0;
1021 	}
1022 
1023 	return -EAGAIN;
1024 }
1025 
1026 static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
1027 		const struct firmware *fw)
1028 {
1029 	struct cyapa_tsg_bin_image *image;
1030 	struct gen5_bl_cmd_head *bl_cmd_head;
1031 	struct gen5_bl_packet_start *bl_packet_start;
1032 	struct gen5_bl_initiate_cmd_data *cmd_data;
1033 	struct gen5_bl_packet_end *bl_packet_end;
1034 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1035 	int cmd_len;
1036 	u16 cmd_data_len;
1037 	u16 cmd_crc = 0;
1038 	u16 meta_data_crc = 0;
1039 	u8 resp_data[11];
1040 	int resp_len;
1041 	int records_num;
1042 	u8 *data;
1043 	int error;
1044 
1045 	/* Try to dump all buffered report data before any send command. */
1046 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1047 
1048 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1049 	bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
1050 	cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
1051 	cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len +
1052 		  sizeof(struct gen5_bl_packet_end);
1053 
1054 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
1055 	put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
1056 	bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
1057 
1058 	bl_packet_start = &bl_cmd_head->packet_start;
1059 	bl_packet_start->sop = GEN5_SOP_KEY;
1060 	bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL;
1061 	/* 8 key bytes and 128 bytes block size */
1062 	put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length);
1063 
1064 	cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data;
1065 	memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE);
1066 
1067 	/* Copy 60 bytes Meta Data Row Parameters */
1068 	image = (struct cyapa_tsg_bin_image *)fw->data;
1069 	records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
1070 				sizeof(struct cyapa_tsg_bin_image_data_record);
1071 	/* APP_INTEGRITY row is always the last row block */
1072 	data = image->records[records_num - 1].record_data;
1073 	memcpy(cmd_data->metadata_raw_parameter, data,
1074 		CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1075 
1076 	meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter,
1077 				CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1078 	put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc);
1079 
1080 	bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
1081 				cmd_data_len);
1082 	cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
1083 		sizeof(struct gen5_bl_packet_start) + cmd_data_len);
1084 	put_unaligned_le16(cmd_crc, &bl_packet_end->crc);
1085 	bl_packet_end->eop = GEN5_EOP_KEY;
1086 
1087 	resp_len = sizeof(resp_data);
1088 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1089 			cmd, cmd_len,
1090 			resp_data, &resp_len, 12000,
1091 			cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
1092 	if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
1093 			resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
1094 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1095 		return error ? error : -EAGAIN;
1096 
1097 	return 0;
1098 }
1099 
1100 static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
1101 {
1102 	if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
1103 		return false;
1104 
1105 	if (buf[0] == 0 && buf[1] == 0)
1106 		return true;
1107 
1108 	/* Exit bootloader failed for some reason. */
1109 	if (len == GEN5_BL_FAIL_EXIT_RESP_LEN &&
1110 			buf[GEN5_RESP_REPORT_ID_OFFSET] ==
1111 				GEN5_BL_RESP_REPORT_ID &&
1112 			buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
1113 			buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY &&
1114 			buf[10] == GEN5_EOP_KEY)
1115 		return true;
1116 
1117 	return false;
1118 }
1119 
1120 static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
1121 {
1122 
1123 	u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
1124 		0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
1125 		0x20, 0xc7, 0x17
1126 	};
1127 	u8 resp_data[11];
1128 	int resp_len;
1129 	int error;
1130 
1131 	resp_len = sizeof(resp_data);
1132 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1133 			bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
1134 			resp_data, &resp_len,
1135 			5000, cyapa_gen5_sort_bl_exit_data, false);
1136 	if (error)
1137 		return error;
1138 
1139 	if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN ||
1140 			resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
1141 				GEN5_BL_RESP_REPORT_ID)
1142 		return -EAGAIN;
1143 
1144 	if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
1145 		return 0;
1146 
1147 	return -ENODEV;
1148 }
1149 
1150 static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
1151 {
1152 	u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
1153 	u8 resp_data[2];
1154 	int resp_len;
1155 	int error;
1156 
1157 	error = cyapa_poll_state(cyapa, 500);
1158 	if (error < 0)
1159 		return error;
1160 	if (cyapa->gen != CYAPA_GEN5)
1161 		return -EINVAL;
1162 
1163 	/* Already in Gen5 BL. Skipping exit. */
1164 	if (cyapa->state == CYAPA_STATE_GEN5_BL)
1165 		return 0;
1166 
1167 	if (cyapa->state != CYAPA_STATE_GEN5_APP)
1168 		return -EAGAIN;
1169 
1170 	/* Try to dump all buffered report data before any send command. */
1171 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1172 
1173 	/*
1174 	 * Send bootloader enter command to trackpad device,
1175 	 * after enter bootloader, the response data is two bytes of 0x00 0x00.
1176 	 */
1177 	resp_len = sizeof(resp_data);
1178 	memset(resp_data, 0, resp_len);
1179 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1180 			cmd, sizeof(cmd),
1181 			resp_data, &resp_len,
1182 			5000, cyapa_gen5_sort_application_launch_data,
1183 			true);
1184 	if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
1185 		return error < 0 ? error : -EAGAIN;
1186 
1187 	cyapa->operational = false;
1188 	cyapa->state = CYAPA_STATE_GEN5_BL;
1189 	return 0;
1190 }
1191 
1192 static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
1193 {
1194 	struct device *dev = &cyapa->client->dev;
1195 	const struct cyapa_tsg_bin_image *image = (const void *)fw->data;
1196 	const struct cyapa_tsg_bin_image_data_record *app_integrity;
1197 	const struct gen5_bl_metadata_row_params *metadata;
1198 	size_t flash_records_count;
1199 	u32 fw_app_start, fw_upgrade_start;
1200 	u16 fw_app_len, fw_upgrade_len;
1201 	u16 app_crc;
1202 	u16 app_integrity_crc;
1203 	int record_index;
1204 	int i;
1205 
1206 	flash_records_count = (fw->size -
1207 			sizeof(struct cyapa_tsg_bin_image_head)) /
1208 			sizeof(struct cyapa_tsg_bin_image_data_record);
1209 
1210 	/*
1211 	 * APP_INTEGRITY row is always the last row block,
1212 	 * and the row id must be 0x01ff.
1213 	 */
1214 	app_integrity = &image->records[flash_records_count - 1];
1215 
1216 	if (app_integrity->flash_array_id != 0x00 ||
1217 	    get_unaligned_be16(&app_integrity->row_number) != 0x01ff) {
1218 		dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
1219 		return -EINVAL;
1220 	}
1221 
1222 	metadata = (const void *)app_integrity->record_data;
1223 
1224 	/* Verify app_integrity crc */
1225 	app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data,
1226 				      CYAPA_TSG_APP_INTEGRITY_SIZE);
1227 	if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) {
1228 		dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
1229 		return -EINVAL;
1230 	}
1231 
1232 	fw_app_start = get_unaligned_le32(&metadata->app_start);
1233 	fw_app_len = get_unaligned_le16(&metadata->app_len);
1234 	fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start);
1235 	fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len);
1236 
1237 	if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE ||
1238 	    fw_app_len % CYAPA_TSG_FW_ROW_SIZE ||
1239 	    fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE ||
1240 	    fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) {
1241 		dev_err(dev, "%s: invalid image alignment.\n", __func__);
1242 		return -EINVAL;
1243 	}
1244 
1245 	/*
1246 	 * Verify application image CRC
1247 	 */
1248 	record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE -
1249 				CYAPA_TSG_IMG_START_ROW_NUM;
1250 	app_crc = 0xffffU;
1251 	for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) {
1252 		const u8 *data = image->records[record_index + i].record_data;
1253 		app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
1254 	}
1255 
1256 	if (app_crc != get_unaligned_le16(&metadata->app_crc)) {
1257 		dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
1258 		return -EINVAL;
1259 	}
1260 
1261 	return 0;
1262 }
1263 
1264 static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
1265 		struct cyapa_tsg_bin_image_data_record *flash_record)
1266 {
1267 	struct gen5_bl_cmd_head *bl_cmd_head;
1268 	struct gen5_bl_packet_start *bl_packet_start;
1269 	struct gen5_bl_flash_row_head *flash_row_head;
1270 	struct gen5_bl_packet_end *bl_packet_end;
1271 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1272 	u16 cmd_len;
1273 	u8 flash_array_id;
1274 	u16 flash_row_id;
1275 	u16 record_len;
1276 	u8 *record_data;
1277 	u16 data_len;
1278 	u16 crc;
1279 	u8 resp_data[11];
1280 	int resp_len;
1281 	int error;
1282 
1283 	flash_array_id = flash_record->flash_array_id;
1284 	flash_row_id = get_unaligned_be16(&flash_record->row_number);
1285 	record_len = get_unaligned_be16(&flash_record->record_len);
1286 	record_data = flash_record->record_data;
1287 
1288 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1289 	bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
1290 	bl_packet_start = &bl_cmd_head->packet_start;
1291 	cmd_len = sizeof(struct gen5_bl_cmd_head) +
1292 		  sizeof(struct gen5_bl_flash_row_head) +
1293 		  CYAPA_TSG_FLASH_MAP_BLOCK_SIZE +
1294 		  sizeof(struct gen5_bl_packet_end);
1295 
1296 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
1297 	/* Don't include 2 bytes register address */
1298 	put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
1299 	bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
1300 	bl_packet_start->sop = GEN5_SOP_KEY;
1301 	bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW;
1302 
1303 	/* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
1304 	data_len = sizeof(struct gen5_bl_flash_row_head) + record_len;
1305 	put_unaligned_le16(data_len, &bl_packet_start->data_length);
1306 
1307 	flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data;
1308 	flash_row_head->flash_array_id = flash_array_id;
1309 	put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id);
1310 	memcpy(flash_row_head->flash_data, record_data, record_len);
1311 
1312 	bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
1313 						      data_len);
1314 	crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
1315 		sizeof(struct gen5_bl_packet_start) + data_len);
1316 	put_unaligned_le16(crc, &bl_packet_end->crc);
1317 	bl_packet_end->eop = GEN5_EOP_KEY;
1318 
1319 	resp_len = sizeof(resp_data);
1320 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1321 			resp_data, &resp_len,
1322 			500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
1323 	if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
1324 			resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
1325 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1326 		return error < 0 ? error : -EAGAIN;
1327 
1328 	return 0;
1329 }
1330 
1331 static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
1332 		const struct firmware *fw)
1333 {
1334 	struct device *dev = &cyapa->client->dev;
1335 	struct cyapa_tsg_bin_image_data_record *flash_record;
1336 	struct cyapa_tsg_bin_image *image =
1337 		(struct cyapa_tsg_bin_image *)fw->data;
1338 	int flash_records_count;
1339 	int i;
1340 	int error;
1341 
1342 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1343 
1344 	flash_records_count =
1345 		(fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
1346 			sizeof(struct cyapa_tsg_bin_image_data_record);
1347 	/*
1348 	 * The last flash row 0x01ff has been written through bl_initiate
1349 	 * command, so DO NOT write flash 0x01ff to trackpad device.
1350 	 */
1351 	for (i = 0; i < (flash_records_count - 1); i++) {
1352 		flash_record = &image->records[i];
1353 		error = cyapa_gen5_write_fw_block(cyapa, flash_record);
1354 		if (error) {
1355 			dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
1356 				__func__, error);
1357 			return error;
1358 		}
1359 	}
1360 
1361 	return 0;
1362 }
1363 
1364 static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
1365 {
1366 	u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
1367 	u8 resp_data[6];
1368 	int resp_len;
1369 	int error;
1370 
1371 	cmd[7] = power_state;
1372 	resp_len = sizeof(resp_data);
1373 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1374 			resp_data, &resp_len,
1375 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1376 	if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
1377 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1378 		return error < 0 ? error : -EINVAL;
1379 
1380 	return 0;
1381 }
1382 
1383 static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
1384 		u8 parameter_id, u16 interval_time)
1385 {
1386 	struct gen5_app_cmd_head *app_cmd_head;
1387 	struct gen5_app_set_parameter_data *parameter_data;
1388 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1389 	int cmd_len;
1390 	u8 resp_data[7];
1391 	int resp_len;
1392 	u8 parameter_size;
1393 	int error;
1394 
1395 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1396 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1397 	parameter_data = (struct gen5_app_set_parameter_data *)
1398 			 app_cmd_head->parameter_data;
1399 	cmd_len = sizeof(struct gen5_app_cmd_head) +
1400 		  sizeof(struct gen5_app_set_parameter_data);
1401 
1402 	switch (parameter_id) {
1403 	case GEN5_PARAMETER_ACT_INTERVL_ID:
1404 		parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1405 		break;
1406 	case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1407 		parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1408 		break;
1409 	case GEN5_PARAMETER_LP_INTRVL_ID:
1410 		parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1411 		break;
1412 	default:
1413 		return -EINVAL;
1414 	}
1415 
1416 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
1417 	/*
1418 	 * Don't include unused parameter value bytes and
1419 	 * 2 bytes register address.
1420 	 */
1421 	put_unaligned_le16(cmd_len - (4 - parameter_size) - 2,
1422 			   &app_cmd_head->length);
1423 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1424 	app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1425 	parameter_data->parameter_id = parameter_id;
1426 	parameter_data->parameter_size = parameter_size;
1427 	put_unaligned_le32((u32)interval_time, &parameter_data->value);
1428 	resp_len = sizeof(resp_data);
1429 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1430 			resp_data, &resp_len,
1431 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1432 	if (error || resp_data[5] != parameter_id ||
1433 		resp_data[6] != parameter_size ||
1434 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER))
1435 		return error < 0 ? error : -EINVAL;
1436 
1437 	return 0;
1438 }
1439 
1440 static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
1441 		u8 parameter_id, u16 *interval_time)
1442 {
1443 	struct gen5_app_cmd_head *app_cmd_head;
1444 	struct gen5_app_get_parameter_data *parameter_data;
1445 	u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1446 	int cmd_len;
1447 	u8 resp_data[11];
1448 	int resp_len;
1449 	u8 parameter_size;
1450 	u16 mask, i;
1451 	int error;
1452 
1453 	memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1454 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1455 	parameter_data = (struct gen5_app_get_parameter_data *)
1456 			 app_cmd_head->parameter_data;
1457 	cmd_len = sizeof(struct gen5_app_cmd_head) +
1458 		  sizeof(struct gen5_app_get_parameter_data);
1459 
1460 	*interval_time = 0;
1461 	switch (parameter_id) {
1462 	case GEN5_PARAMETER_ACT_INTERVL_ID:
1463 		parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1464 		break;
1465 	case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1466 		parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1467 		break;
1468 	case GEN5_PARAMETER_LP_INTRVL_ID:
1469 		parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1470 		break;
1471 	default:
1472 		return -EINVAL;
1473 	}
1474 
1475 	put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1476 	/* Don't include 2 bytes register address */
1477 	put_unaligned_le16(cmd_len - 2, &app_cmd_head->length);
1478 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1479 	app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER;
1480 	parameter_data->parameter_id = parameter_id;
1481 
1482 	resp_len = sizeof(resp_data);
1483 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1484 			resp_data, &resp_len,
1485 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1486 	if (error || resp_data[5] != parameter_id || resp_data[6] == 0 ||
1487 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER))
1488 		return error < 0 ? error : -EINVAL;
1489 
1490 	mask = 0;
1491 	for (i = 0; i < parameter_size; i++)
1492 		mask |= (0xff << (i * 8));
1493 	*interval_time = get_unaligned_le16(&resp_data[7]) & mask;
1494 
1495 	return 0;
1496 }
1497 
1498 static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
1499 {
1500 	struct gen5_app_cmd_head *app_cmd_head;
1501 	u8 cmd[10];
1502 	u8 resp_data[7];
1503 	int resp_len;
1504 	int error;
1505 
1506 	memset(cmd, 0, sizeof(cmd));
1507 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1508 
1509 	put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1510 	put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
1511 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1512 	app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1513 	app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
1514 	app_cmd_head->parameter_data[1] = 0x01;
1515 	app_cmd_head->parameter_data[2] = 0x01;
1516 	resp_len = sizeof(resp_data);
1517 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1518 			resp_data, &resp_len,
1519 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1520 	if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
1521 		!VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) ||
1522 		resp_data[6] != 0x01)
1523 		return error < 0 ? error : -EINVAL;
1524 
1525 	return 0;
1526 }
1527 
1528 static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state)
1529 {
1530 	u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
1531 	u8 resp_data[5];
1532 	int resp_len;
1533 	int error;
1534 
1535 	cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK;
1536 	resp_len = sizeof(resp_data);
1537 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1538 			resp_data, &resp_len,
1539 			500, cyapa_gen5_sort_deep_sleep_data, false);
1540 	if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state))
1541 		return -EINVAL;
1542 
1543 	return 0;
1544 }
1545 
1546 static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
1547 		u8 power_mode, u16 sleep_time)
1548 {
1549 	struct device *dev = &cyapa->client->dev;
1550 	u8 power_state;
1551 	int error;
1552 
1553 	if (cyapa->state != CYAPA_STATE_GEN5_APP)
1554 		return 0;
1555 
1556 	/* Dump all the report data before do power mode commmands. */
1557 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1558 
1559 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
1560 		/*
1561 		 * Assume TP in deep sleep mode when driver is loaded,
1562 		 * avoid driver unload and reload command IO issue caused by TP
1563 		 * has been set into deep sleep mode when unloading.
1564 		 */
1565 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1566 	}
1567 
1568 	if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) &&
1569 			GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
1570 		if (cyapa_gen5_get_interval_time(cyapa,
1571 				GEN5_PARAMETER_LP_INTRVL_ID,
1572 				&cyapa->dev_sleep_time) != 0)
1573 			GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
1574 
1575 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) {
1576 		if (power_mode == PWR_MODE_OFF ||
1577 			power_mode == PWR_MODE_FULL_ACTIVE ||
1578 			power_mode == PWR_MODE_BTN_ONLY ||
1579 			GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
1580 			/* Has in correct power mode state, early return. */
1581 			return 0;
1582 		}
1583 	}
1584 
1585 	if (power_mode == PWR_MODE_OFF) {
1586 		error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF);
1587 		if (error) {
1588 			dev_err(dev, "enter deep sleep fail: %d\n", error);
1589 			return error;
1590 		}
1591 
1592 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1593 		return 0;
1594 	}
1595 
1596 	/*
1597 	 * When trackpad in power off mode, it cannot change to other power
1598 	 * state directly, must be wake up from sleep firstly, then
1599 	 * continue to do next power sate change.
1600 	 */
1601 	if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
1602 		error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON);
1603 		if (error) {
1604 			dev_err(dev, "deep sleep wake fail: %d\n", error);
1605 			return error;
1606 		}
1607 	}
1608 
1609 	if (power_mode == PWR_MODE_FULL_ACTIVE) {
1610 		error = cyapa_gen5_change_power_state(cyapa,
1611 				GEN5_POWER_STATE_ACTIVE);
1612 		if (error) {
1613 			dev_err(dev, "change to active fail: %d\n", error);
1614 			return error;
1615 		}
1616 
1617 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
1618 	} else if (power_mode == PWR_MODE_BTN_ONLY) {
1619 		error = cyapa_gen5_change_power_state(cyapa,
1620 				GEN5_POWER_STATE_BTN_ONLY);
1621 		if (error) {
1622 			dev_err(dev, "fail to button only mode: %d\n", error);
1623 			return error;
1624 		}
1625 
1626 		GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
1627 	} else {
1628 		/*
1629 		 * Continue to change power mode even failed to set
1630 		 * interval time, it won't affect the power mode change.
1631 		 * except the sleep interval time is not correct.
1632 		 */
1633 		if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) ||
1634 				sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa))
1635 			if (cyapa_gen5_set_interval_time(cyapa,
1636 					GEN5_PARAMETER_LP_INTRVL_ID,
1637 					sleep_time) == 0)
1638 				GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
1639 
1640 		if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
1641 			power_state = GEN5_POWER_STATE_READY;
1642 		else
1643 			power_state = GEN5_POWER_STATE_IDLE;
1644 		error = cyapa_gen5_change_power_state(cyapa, power_state);
1645 		if (error) {
1646 			dev_err(dev, "set power state to 0x%02x failed: %d\n",
1647 				power_state, error);
1648 			return error;
1649 		}
1650 
1651 		/*
1652 		 * Disable pip report for a little time, firmware will
1653 		 * re-enable it automatically. It's used to fix the issue
1654 		 * that trackpad unable to report signal to wake system up
1655 		 * in the special situation that system is in suspending, and
1656 		 * at the same time, user touch trackpad to wake system up.
1657 		 * This function can avoid the data to be buffured when system
1658 		 * is suspending which may cause interrput line unable to be
1659 		 * asserted again.
1660 		 */
1661 		cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1662 		cyapa_gen5_disable_pip_report(cyapa);
1663 
1664 		GEN5_DEV_SET_PWR_STATE(cyapa,
1665 			cyapa_sleep_time_to_pwr_cmd(sleep_time));
1666 	}
1667 
1668 	return 0;
1669 }
1670 
1671 static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
1672 {
1673 	u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
1674 	u8 resp_data[6];
1675 	int resp_len;
1676 	int error;
1677 
1678 	/* Try to dump all buffered data before doing command. */
1679 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1680 
1681 	resp_len = sizeof(resp_data);
1682 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1683 			cmd, sizeof(cmd),
1684 			resp_data, &resp_len,
1685 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1686 	if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
1687 		return -EINVAL;
1688 
1689 	/* Try to dump all buffered data when resuming scanning. */
1690 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1691 
1692 	return 0;
1693 }
1694 
1695 static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
1696 {
1697 	u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
1698 	u8 resp_data[6];
1699 	int resp_len;
1700 	int error;
1701 
1702 	/* Try to dump all buffered data before doing command. */
1703 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1704 
1705 	resp_len = sizeof(resp_data);
1706 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1707 			cmd, sizeof(cmd),
1708 			resp_data, &resp_len,
1709 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1710 	if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
1711 		return -EINVAL;
1712 
1713 	/* Try to dump all buffered data when suspending scanning. */
1714 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1715 
1716 	return 0;
1717 }
1718 
1719 static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa,
1720 		u8 calibrate_sensing_mode_type)
1721 {
1722 	struct gen5_app_cmd_head *app_cmd_head;
1723 	u8 cmd[8];
1724 	u8 resp_data[6];
1725 	int resp_len;
1726 	int error;
1727 
1728 	/* Try to dump all buffered data before doing command. */
1729 	cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1730 
1731 	memset(cmd, 0, sizeof(cmd));
1732 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1733 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
1734 	put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
1735 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1736 	app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE;
1737 	app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type;
1738 	resp_len = sizeof(resp_data);
1739 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1740 			cmd, sizeof(cmd),
1741 			resp_data, &resp_len,
1742 			5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1743 	if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) ||
1744 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1745 		return error < 0 ? error : -EAGAIN;
1746 
1747 	return 0;
1748 }
1749 
1750 static ssize_t cyapa_gen5_do_calibrate(struct device *dev,
1751 				     struct device_attribute *attr,
1752 				     const char *buf, size_t count)
1753 {
1754 	struct cyapa *cyapa = dev_get_drvdata(dev);
1755 	int error, calibrate_error;
1756 
1757 	/* 1. Suspend Scanning*/
1758 	error = cyapa_gen5_suspend_scanning(cyapa);
1759 	if (error)
1760 		return error;
1761 
1762 	/* 2. Do mutual capacitance fine calibrate. */
1763 	calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
1764 				CYAPA_SENSING_MODE_MUTUAL_CAP_FINE);
1765 	if (calibrate_error)
1766 		goto resume_scanning;
1767 
1768 	/* 3. Do self capacitance calibrate. */
1769 	calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
1770 				CYAPA_SENSING_MODE_SELF_CAP);
1771 	if (calibrate_error)
1772 		goto resume_scanning;
1773 
1774 resume_scanning:
1775 	/* 4. Resume Scanning*/
1776 	error = cyapa_gen5_resume_scanning(cyapa);
1777 	if (error || calibrate_error)
1778 		return error ? error : calibrate_error;
1779 
1780 	return count;
1781 }
1782 
1783 static s32 twos_complement_to_s32(s32 value, int num_bits)
1784 {
1785 	if (value >> (num_bits - 1))
1786 		value |=  -1 << num_bits;
1787 	return value;
1788 }
1789 
1790 static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
1791 {
1792 	int data_size;
1793 	bool big_endian;
1794 	bool unsigned_type;
1795 	s32 value;
1796 
1797 	data_size = (data_format & 0x07);
1798 	big_endian = ((data_format & 0x10) == 0x00);
1799 	unsigned_type = ((data_format & 0x20) == 0x00);
1800 
1801 	if (buf_len < data_size)
1802 		return 0;
1803 
1804 	switch (data_size) {
1805 	case 1:
1806 		value  = buf[0];
1807 		break;
1808 	case 2:
1809 		if (big_endian)
1810 			value = get_unaligned_be16(buf);
1811 		else
1812 			value = get_unaligned_le16(buf);
1813 		break;
1814 	case 4:
1815 		if (big_endian)
1816 			value = get_unaligned_be32(buf);
1817 		else
1818 			value = get_unaligned_le32(buf);
1819 		break;
1820 	default:
1821 		/* Should not happen, just as default case here. */
1822 		value = 0;
1823 		break;
1824 	}
1825 
1826 	if (!unsigned_type)
1827 		value = twos_complement_to_s32(value, data_size * 8);
1828 
1829 	return value;
1830 }
1831 
1832 static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa,
1833 		int *electrodes_rx, int *electrodes_tx)
1834 {
1835 	if (cyapa->electrodes_rx != 0) {
1836 		*electrodes_rx = cyapa->electrodes_rx;
1837 		*electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ?
1838 				cyapa->electrodes_y : cyapa->electrodes_x;
1839 	} else {
1840 		*electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y);
1841 		*electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y);
1842 	}
1843 }
1844 
1845 /*
1846  * Read all the global mutual or self idac data or mutual or self local PWC
1847  * data based on the @idac_data_type.
1848  * If the input value of @data_size is 0, then means read global mutual or
1849  * self idac data. For read global mutual idac data, @idac_max, @idac_min and
1850  * @idac_ave are in order used to return the max value of global mutual idac
1851  * data, the min value of global mutual idac and the average value of the
1852  * global mutual idac data. For read global self idac data, @idac_max is used
1853  * to return the global self cap idac data in Rx direction, @idac_min is used
1854  * to return the global self cap idac data in Tx direction. @idac_ave is not
1855  * used.
1856  * If the input value of @data_size is not 0, than means read the mutual or
1857  * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
1858  * return the max, min and average value of the mutual or self local PWC data.
1859  * Note, in order to raed mutual local PWC data, must read invoke this function
1860  * to read the mutual global idac data firstly to set the correct Rx number
1861  * value, otherwise, the read mutual idac and PWC data may not correct.
1862  */
1863 static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
1864 		u8 cmd_code, u8 idac_data_type, int *data_size,
1865 		int *idac_max, int *idac_min, int *idac_ave)
1866 {
1867 	struct gen5_app_cmd_head *cmd_head;
1868 	u8 cmd[12];
1869 	u8 resp_data[256];
1870 	int resp_len;
1871 	int read_len;
1872 	int value;
1873 	u16 offset;
1874 	int read_elements;
1875 	bool read_global_idac;
1876 	int sum, count, max_element_cnt;
1877 	int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
1878 	int electrodes_rx, electrodes_tx;
1879 	int i;
1880 	int error;
1881 
1882 	if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
1883 		(idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
1884 		idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
1885 		!data_size || !idac_max || !idac_min || !idac_ave)
1886 		return -EINVAL;
1887 
1888 	*idac_max = INT_MIN;
1889 	*idac_min = INT_MAX;
1890 	sum = count = tmp_count = 0;
1891 	electrodes_rx = electrodes_tx = 0;
1892 	if (*data_size == 0) {
1893 		/*
1894 		 * Read global idac values firstly.
1895 		 * Currently, no idac data exceed 4 bytes.
1896 		 */
1897 		read_global_idac = true;
1898 		offset = 0;
1899 		*data_size = 4;
1900 		tmp_max = INT_MIN;
1901 		tmp_min = INT_MAX;
1902 		tmp_ave = tmp_sum = tmp_count = 0;
1903 
1904 		if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1905 			if (cyapa->aligned_electrodes_rx == 0) {
1906 				cyapa_gen5_guess_electrodes(cyapa,
1907 					&electrodes_rx, &electrodes_tx);
1908 				cyapa->aligned_electrodes_rx =
1909 					(electrodes_rx + 3) & ~3u;
1910 			}
1911 			max_element_cnt =
1912 				(cyapa->aligned_electrodes_rx + 7) & ~7u;
1913 		} else {
1914 			max_element_cnt = 2;
1915 		}
1916 	} else {
1917 		read_global_idac = false;
1918 		if (*data_size > 4)
1919 			*data_size = 4;
1920 		/* Calculate the start offset in bytes of local PWC data. */
1921 		if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1922 			offset = cyapa->aligned_electrodes_rx * (*data_size);
1923 			if (cyapa->electrodes_rx == cyapa->electrodes_x)
1924 				electrodes_tx = cyapa->electrodes_y;
1925 			else
1926 				electrodes_tx = cyapa->electrodes_x;
1927 			max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
1928 						~7u) * electrodes_tx;
1929 		} else {
1930 			offset = 2;
1931 			max_element_cnt = cyapa->electrodes_x +
1932 						cyapa->electrodes_y;
1933 			max_element_cnt = (max_element_cnt + 3) & ~3u;
1934 		}
1935 	}
1936 
1937 	memset(cmd, 0, sizeof(cmd));
1938 	cmd_head = (struct gen5_app_cmd_head *)cmd;
1939 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr);
1940 	put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length);
1941 	cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1942 	cmd_head->cmd_code = cmd_code;
1943 	do {
1944 		read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) /
1945 				(*data_size);
1946 		read_elements = min(read_elements, max_element_cnt - count);
1947 		read_len = read_elements * (*data_size);
1948 
1949 		put_unaligned_le16(offset, &cmd_head->parameter_data[0]);
1950 		put_unaligned_le16(read_len, &cmd_head->parameter_data[2]);
1951 		cmd_head->parameter_data[4] = idac_data_type;
1952 		resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
1953 		error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1954 				cmd, sizeof(cmd),
1955 				resp_data, &resp_len,
1956 				500, cyapa_gen5_sort_tsg_pip_app_resp_data,
1957 				true);
1958 		if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
1959 				!VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
1960 				!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
1961 				resp_data[6] != idac_data_type)
1962 			return (error < 0) ? error : -EAGAIN;
1963 		read_len = get_unaligned_le16(&resp_data[7]);
1964 		if (read_len == 0)
1965 			break;
1966 
1967 		*data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
1968 		if (read_len < *data_size)
1969 			return -EINVAL;
1970 
1971 		if (read_global_idac &&
1972 			idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
1973 			/* Rx's self global idac data. */
1974 			*idac_max = cyapa_parse_structure_data(
1975 				resp_data[9],
1976 				&resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET],
1977 				*data_size);
1978 			/* Tx's self global idac data. */
1979 			*idac_min = cyapa_parse_structure_data(
1980 				resp_data[9],
1981 				&resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET +
1982 					   *data_size],
1983 				*data_size);
1984 			break;
1985 		}
1986 
1987 		/* Read mutual global idac or local mutual/self PWC data. */
1988 		offset += read_len;
1989 		for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET);
1990 				i += *data_size) {
1991 			value = cyapa_parse_structure_data(resp_data[9],
1992 					&resp_data[i], *data_size);
1993 			*idac_min = min(value, *idac_min);
1994 			*idac_max = max(value, *idac_max);
1995 
1996 			if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
1997 				tmp_count < cyapa->aligned_electrodes_rx &&
1998 				read_global_idac) {
1999 				/*
2000 				 * The value gap betwen global and local mutual
2001 				 * idac data must bigger than 50%.
2002 				 * Normally, global value bigger than 50,
2003 				 * local values less than 10.
2004 				 */
2005 				if (!tmp_ave || value > tmp_ave / 2) {
2006 					tmp_min = min(value, tmp_min);
2007 					tmp_max = max(value, tmp_max);
2008 					tmp_sum += value;
2009 					tmp_count++;
2010 
2011 					tmp_ave = tmp_sum / tmp_count;
2012 				}
2013 			}
2014 
2015 			sum += value;
2016 			count++;
2017 
2018 			if (count >= max_element_cnt)
2019 				goto out;
2020 		}
2021 	} while (true);
2022 
2023 out:
2024 	*idac_ave = count ? (sum / count) : 0;
2025 
2026 	if (read_global_idac &&
2027 		idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
2028 		if (tmp_count == 0)
2029 			return 0;
2030 
2031 		if (tmp_count == cyapa->aligned_electrodes_rx) {
2032 			cyapa->electrodes_rx = cyapa->electrodes_rx ?
2033 				cyapa->electrodes_rx : electrodes_rx;
2034 		} else if (tmp_count == electrodes_rx) {
2035 			cyapa->electrodes_rx = cyapa->electrodes_rx ?
2036 				cyapa->electrodes_rx : electrodes_rx;
2037 			cyapa->aligned_electrodes_rx = electrodes_rx;
2038 		} else {
2039 			cyapa->electrodes_rx = cyapa->electrodes_rx ?
2040 				cyapa->electrodes_rx : electrodes_tx;
2041 			cyapa->aligned_electrodes_rx = tmp_count;
2042 		}
2043 
2044 		*idac_min = tmp_min;
2045 		*idac_max = tmp_max;
2046 		*idac_ave = tmp_ave;
2047 	}
2048 
2049 	return 0;
2050 }
2051 
2052 static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
2053 	int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
2054 	int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
2055 {
2056 	int data_size;
2057 	int error;
2058 
2059 	*gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
2060 	*lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
2061 
2062 	data_size = 0;
2063 	error = cyapa_gen5_read_idac_data(cyapa,
2064 		GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2065 		GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2066 		&data_size,
2067 		gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
2068 	if (error)
2069 		return error;
2070 
2071 	error = cyapa_gen5_read_idac_data(cyapa,
2072 		GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2073 		GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2074 		&data_size,
2075 		lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
2076 	return error;
2077 }
2078 
2079 static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
2080 		int *gidac_self_rx, int *gidac_self_tx,
2081 		int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
2082 {
2083 	int data_size;
2084 	int error;
2085 
2086 	*gidac_self_rx = *gidac_self_tx = 0;
2087 	*lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
2088 
2089 	data_size = 0;
2090 	error = cyapa_gen5_read_idac_data(cyapa,
2091 		GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2092 		GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2093 		&data_size,
2094 		lidac_self_max, lidac_self_min, lidac_self_ave);
2095 	if (error)
2096 		return error;
2097 	*gidac_self_rx = *lidac_self_max;
2098 	*gidac_self_tx = *lidac_self_min;
2099 
2100 	error = cyapa_gen5_read_idac_data(cyapa,
2101 		GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2102 		GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2103 		&data_size,
2104 		lidac_self_max, lidac_self_min, lidac_self_ave);
2105 	return error;
2106 }
2107 
2108 static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
2109 {
2110 	struct gen5_app_cmd_head *app_cmd_head;
2111 	u8 cmd[7];
2112 	u8 resp_data[6];
2113 	int resp_len;
2114 	int error;
2115 
2116 	memset(cmd, 0, sizeof(cmd));
2117 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
2118 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
2119 	put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
2120 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
2121 	app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN;
2122 	resp_len = sizeof(resp_data);
2123 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2124 			cmd, sizeof(cmd),
2125 			resp_data, &resp_len,
2126 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
2127 	if (error || resp_len != sizeof(resp_data) ||
2128 			!VALID_CMD_RESP_HEADER(resp_data,
2129 				GEN5_CMD_EXECUTE_PANEL_SCAN) ||
2130 			!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
2131 		return error ? error : -EAGAIN;
2132 
2133 	return 0;
2134 }
2135 
2136 static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
2137 		u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
2138 		int *raw_data_max, int *raw_data_min, int *raw_data_ave,
2139 		u8 *buffer)
2140 {
2141 	struct gen5_app_cmd_head *app_cmd_head;
2142 	struct gen5_retrieve_panel_scan_data *panel_sacn_data;
2143 	u8 cmd[12];
2144 	u8 resp_data[256];  /* Max bytes can transfer one time. */
2145 	int resp_len;
2146 	int read_elements;
2147 	int read_len;
2148 	u16 offset;
2149 	s32 value;
2150 	int sum, count;
2151 	int data_size;
2152 	s32 *intp;
2153 	int i;
2154 	int error;
2155 
2156 	if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
2157 		(raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
2158 		!raw_data_max || !raw_data_min || !raw_data_ave)
2159 		return -EINVAL;
2160 
2161 	intp = (s32 *)buffer;
2162 	*raw_data_max = INT_MIN;
2163 	*raw_data_min = INT_MAX;
2164 	sum = count = 0;
2165 	offset = 0;
2166 	/* Assume max element size is 4 currently. */
2167 	read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4;
2168 	read_len = read_elements * 4;
2169 	app_cmd_head = (struct gen5_app_cmd_head *)cmd;
2170 	put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
2171 	put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
2172 	app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
2173 	app_cmd_head->cmd_code = cmd_code;
2174 	panel_sacn_data = (struct gen5_retrieve_panel_scan_data *)
2175 			app_cmd_head->parameter_data;
2176 	do {
2177 		put_unaligned_le16(offset, &panel_sacn_data->read_offset);
2178 		put_unaligned_le16(read_elements,
2179 			&panel_sacn_data->read_elements);
2180 		panel_sacn_data->data_id = raw_data_type;
2181 
2182 		resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
2183 		error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2184 			cmd, sizeof(cmd),
2185 			resp_data, &resp_len,
2186 			500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
2187 		if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
2188 				!VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
2189 				!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
2190 				resp_data[6] != raw_data_type)
2191 			return error ? error : -EAGAIN;
2192 
2193 		read_elements = get_unaligned_le16(&resp_data[7]);
2194 		if (read_elements == 0)
2195 			break;
2196 
2197 		data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
2198 		offset += read_elements;
2199 		if (read_elements) {
2200 			for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET;
2201 			     i < (read_elements * data_size +
2202 					GEN5_RESP_DATA_STRUCTURE_OFFSET);
2203 			     i += data_size) {
2204 				value = cyapa_parse_structure_data(resp_data[9],
2205 						&resp_data[i], data_size);
2206 				*raw_data_min = min(value, *raw_data_min);
2207 				*raw_data_max = max(value, *raw_data_max);
2208 
2209 				if (intp)
2210 					put_unaligned_le32(value, &intp[count]);
2211 
2212 				sum += value;
2213 				count++;
2214 
2215 			}
2216 		}
2217 
2218 		if (count >= raw_data_max_num)
2219 			break;
2220 
2221 		read_elements = (sizeof(resp_data) -
2222 				GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size;
2223 		read_len = read_elements * data_size;
2224 	} while (true);
2225 
2226 	*raw_data_ave = count ? (sum / count) : 0;
2227 
2228 	return 0;
2229 }
2230 
2231 static ssize_t cyapa_gen5_show_baseline(struct device *dev,
2232 				   struct device_attribute *attr, char *buf)
2233 {
2234 	struct cyapa *cyapa = dev_get_drvdata(dev);
2235 	int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
2236 	int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
2237 	int gidac_self_rx, gidac_self_tx;
2238 	int lidac_self_max, lidac_self_min, lidac_self_ave;
2239 	int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
2240 	int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
2241 	int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
2242 	int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
2243 	int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
2244 	int self_baseline_max, self_baseline_min, self_baseline_ave;
2245 	int error, resume_error;
2246 	int size;
2247 
2248 	if (cyapa->state != CYAPA_STATE_GEN5_APP)
2249 		return -EBUSY;
2250 
2251 	/* 1. Suspend Scanning*/
2252 	error = cyapa_gen5_suspend_scanning(cyapa);
2253 	if (error)
2254 		return error;
2255 
2256 	/* 2.  Read global and local mutual IDAC data. */
2257 	gidac_self_rx = gidac_self_tx = 0;
2258 	error = cyapa_gen5_read_mutual_idac_data(cyapa,
2259 				&gidac_mutual_max, &gidac_mutual_min,
2260 				&gidac_mutual_ave, &lidac_mutual_max,
2261 				&lidac_mutual_min, &lidac_mutual_ave);
2262 	if (error)
2263 		goto resume_scanning;
2264 
2265 	/* 3.  Read global and local self IDAC data. */
2266 	error = cyapa_gen5_read_self_idac_data(cyapa,
2267 				&gidac_self_rx, &gidac_self_tx,
2268 				&lidac_self_max, &lidac_self_min,
2269 				&lidac_self_ave);
2270 	if (error)
2271 		goto resume_scanning;
2272 
2273 	/* 4. Execuate panel scan. It must be executed before read data. */
2274 	error = cyapa_gen5_execute_panel_scan(cyapa);
2275 	if (error)
2276 		goto resume_scanning;
2277 
2278 	/* 5. Retrieve panel scan, mutual cap raw data. */
2279 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2280 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2281 				GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
2282 				cyapa->electrodes_x * cyapa->electrodes_y,
2283 				&raw_cap_mutual_max, &raw_cap_mutual_min,
2284 				&raw_cap_mutual_ave,
2285 				NULL);
2286 	if (error)
2287 		goto resume_scanning;
2288 
2289 	/* 6. Retrieve panel scan, self cap raw data. */
2290 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2291 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2292 				GEN5_PANEL_SCAN_SELF_RAW_DATA,
2293 				cyapa->electrodes_x + cyapa->electrodes_y,
2294 				&raw_cap_self_max, &raw_cap_self_min,
2295 				&raw_cap_self_ave,
2296 				NULL);
2297 	if (error)
2298 		goto resume_scanning;
2299 
2300 	/* 7. Retrieve panel scan, mutual cap diffcount raw data. */
2301 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2302 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2303 				GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
2304 				cyapa->electrodes_x * cyapa->electrodes_y,
2305 				&mutual_diffdata_max, &mutual_diffdata_min,
2306 				&mutual_diffdata_ave,
2307 				NULL);
2308 	if (error)
2309 		goto resume_scanning;
2310 
2311 	/* 8. Retrieve panel scan, self cap diffcount raw data. */
2312 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2313 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2314 				GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
2315 				cyapa->electrodes_x + cyapa->electrodes_y,
2316 				&self_diffdata_max, &self_diffdata_min,
2317 				&self_diffdata_ave,
2318 				NULL);
2319 	if (error)
2320 		goto resume_scanning;
2321 
2322 	/* 9. Retrieve panel scan, mutual cap baseline raw data. */
2323 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2324 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2325 				GEN5_PANEL_SCAN_MUTUAL_BASELINE,
2326 				cyapa->electrodes_x * cyapa->electrodes_y,
2327 				&mutual_baseline_max, &mutual_baseline_min,
2328 				&mutual_baseline_ave,
2329 				NULL);
2330 	if (error)
2331 		goto resume_scanning;
2332 
2333 	/* 10. Retrieve panel scan, self cap baseline raw data. */
2334 	error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2335 				GEN5_CMD_RETRIEVE_PANEL_SCAN,
2336 				GEN5_PANEL_SCAN_SELF_BASELINE,
2337 				cyapa->electrodes_x + cyapa->electrodes_y,
2338 				&self_baseline_max, &self_baseline_min,
2339 				&self_baseline_ave,
2340 				NULL);
2341 	if (error)
2342 		goto resume_scanning;
2343 
2344 resume_scanning:
2345 	/* 11. Resume Scanning*/
2346 	resume_error = cyapa_gen5_resume_scanning(cyapa);
2347 	if (resume_error || error)
2348 		return resume_error ? resume_error : error;
2349 
2350 	/* 12. Output data strings */
2351 	size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
2352 		gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
2353 		lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
2354 		gidac_self_rx, gidac_self_tx,
2355 		lidac_self_min, lidac_self_max, lidac_self_ave);
2356 	size += scnprintf(buf + size, PAGE_SIZE - size,
2357 		"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
2358 		raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
2359 		raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
2360 		mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
2361 		self_diffdata_min, self_diffdata_max, self_diffdata_ave,
2362 		mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
2363 		self_baseline_min, self_baseline_max, self_baseline_ave);
2364 	return size;
2365 }
2366 
2367 static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
2368 		u8 *buf, int len)
2369 {
2370 	/* Check the report id and command code */
2371 	if (VALID_CMD_RESP_HEADER(buf, 0x02))
2372 		return true;
2373 
2374 	return false;
2375 }
2376 
2377 static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
2378 {
2379 	u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
2380 		0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
2381 	};
2382 	u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN];
2383 	int resp_len;
2384 	int error;
2385 
2386 	resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN;
2387 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2388 			bl_query_data_cmd, sizeof(bl_query_data_cmd),
2389 			resp_data, &resp_len,
2390 			500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false);
2391 	if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN ||
2392 		!GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
2393 		return error ? error : -EIO;
2394 
2395 	memcpy(&cyapa->product_id[0], &resp_data[8], 5);
2396 	cyapa->product_id[5] = '-';
2397 	memcpy(&cyapa->product_id[6], &resp_data[13], 6);
2398 	cyapa->product_id[12] = '-';
2399 	memcpy(&cyapa->product_id[13], &resp_data[19], 2);
2400 	cyapa->product_id[15] = '\0';
2401 
2402 	cyapa->fw_maj_ver = resp_data[22];
2403 	cyapa->fw_min_ver = resp_data[23];
2404 
2405 	return 0;
2406 }
2407 
2408 static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
2409 {
2410 	u8 get_system_information[] = {
2411 		0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
2412 	};
2413 	u8 resp_data[71];
2414 	int resp_len;
2415 	u16 product_family;
2416 	int error;
2417 
2418 	resp_len = sizeof(resp_data);
2419 	error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2420 			get_system_information, sizeof(get_system_information),
2421 			resp_data, &resp_len,
2422 			2000, cyapa_gen5_sort_system_info_data, false);
2423 	if (error || resp_len < sizeof(resp_data))
2424 		return error ? error : -EIO;
2425 
2426 	product_family = get_unaligned_le16(&resp_data[7]);
2427 	if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
2428 		GEN5_PRODUCT_FAMILY_TRACKPAD)
2429 		return -EINVAL;
2430 
2431 	cyapa->fw_maj_ver = resp_data[15];
2432 	cyapa->fw_min_ver = resp_data[16];
2433 
2434 	cyapa->electrodes_x = resp_data[52];
2435 	cyapa->electrodes_y = resp_data[53];
2436 
2437 	cyapa->physical_size_x =  get_unaligned_le16(&resp_data[54]) / 100;
2438 	cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
2439 
2440 	cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
2441 	cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
2442 
2443 	cyapa->max_z = get_unaligned_le16(&resp_data[62]);
2444 
2445 	cyapa->x_origin = resp_data[64] & 0x01;
2446 	cyapa->y_origin = resp_data[65] & 0x01;
2447 
2448 	cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
2449 
2450 	memcpy(&cyapa->product_id[0], &resp_data[33], 5);
2451 	cyapa->product_id[5] = '-';
2452 	memcpy(&cyapa->product_id[6], &resp_data[38], 6);
2453 	cyapa->product_id[12] = '-';
2454 	memcpy(&cyapa->product_id[13], &resp_data[44], 2);
2455 	cyapa->product_id[15] = '\0';
2456 
2457 	if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
2458 		!cyapa->physical_size_x || !cyapa->physical_size_y ||
2459 		!cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
2460 		return -EINVAL;
2461 
2462 	return 0;
2463 }
2464 
2465 static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
2466 {
2467 	struct device *dev = &cyapa->client->dev;
2468 	int error;
2469 
2470 	if (cyapa->gen != CYAPA_GEN5)
2471 		return -ENODEV;
2472 
2473 	switch (cyapa->state) {
2474 	case CYAPA_STATE_GEN5_BL:
2475 		error = cyapa_gen5_bl_exit(cyapa);
2476 		if (error) {
2477 			/* Rry to update trackpad product information. */
2478 			cyapa_gen5_bl_query_data(cyapa);
2479 			goto out;
2480 		}
2481 
2482 		cyapa->state = CYAPA_STATE_GEN5_APP;
2483 
2484 	case CYAPA_STATE_GEN5_APP:
2485 		/*
2486 		 * If trackpad device in deep sleep mode,
2487 		 * the app command will fail.
2488 		 * So always try to reset trackpad device to full active when
2489 		 * the device state is requeried.
2490 		 */
2491 		error = cyapa_gen5_set_power_mode(cyapa,
2492 				PWR_MODE_FULL_ACTIVE, 0);
2493 		if (error)
2494 			dev_warn(dev, "%s: failed to set power active mode.\n",
2495 				__func__);
2496 
2497 		/* Get trackpad product information. */
2498 		error = cyapa_gen5_get_query_data(cyapa);
2499 		if (error)
2500 			goto out;
2501 		/* Only support product ID starting with CYTRA */
2502 		if (memcmp(cyapa->product_id, product_id,
2503 				strlen(product_id)) != 0) {
2504 			dev_err(dev, "%s: unknown product ID (%s)\n",
2505 				__func__, cyapa->product_id);
2506 			error = -EINVAL;
2507 		}
2508 		break;
2509 	default:
2510 		error = -EINVAL;
2511 	}
2512 
2513 out:
2514 	return error;
2515 }
2516 
2517 /*
2518  * Return false, do not continue process
2519  * Return true, continue process.
2520  */
2521 static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
2522 {
2523 	struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
2524 	int length;
2525 
2526 	if (atomic_read(&gen5_pip->cmd_issued)) {
2527 		/* Polling command response data. */
2528 		if (gen5_pip->is_irq_mode == false)
2529 			return false;
2530 
2531 		/*
2532 		 * Read out all none command response data.
2533 		 * these output data may caused by user put finger on
2534 		 * trackpad when host waiting the command response.
2535 		 */
2536 		cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf,
2537 			GEN5_RESP_LENGTH_SIZE);
2538 		length = get_unaligned_le16(gen5_pip->irq_cmd_buf);
2539 		length = (length <= GEN5_RESP_LENGTH_SIZE) ?
2540 				GEN5_RESP_LENGTH_SIZE : length;
2541 		if (length > GEN5_RESP_LENGTH_SIZE)
2542 			cyapa_i2c_pip_read(cyapa,
2543 				gen5_pip->irq_cmd_buf, length);
2544 
2545 		if (!(gen5_pip->resp_sort_func &&
2546 			gen5_pip->resp_sort_func(cyapa,
2547 				gen5_pip->irq_cmd_buf, length))) {
2548 			/*
2549 			 * Cover the Gen5 V1 firmware issue.
2550 			 * The issue is there is no interrut will be
2551 			 * asserted to notityf host to read a command
2552 			 * data out when always has finger touch on
2553 			 * trackpad during the command is issued to
2554 			 * trackad device.
2555 			 * This issue has the scenario is that,
2556 			 * user always has his fingers touched on
2557 			 * trackpad device when booting/rebooting
2558 			 * their chrome book.
2559 			 */
2560 			length = 0;
2561 			if (gen5_pip->resp_len)
2562 				length = *gen5_pip->resp_len;
2563 			cyapa_empty_pip_output_data(cyapa,
2564 					gen5_pip->resp_data,
2565 					&length,
2566 					gen5_pip->resp_sort_func);
2567 			if (gen5_pip->resp_len && length != 0) {
2568 				*gen5_pip->resp_len = length;
2569 				atomic_dec(&gen5_pip->cmd_issued);
2570 				complete(&gen5_pip->cmd_ready);
2571 			}
2572 			return false;
2573 		}
2574 
2575 		if (gen5_pip->resp_data && gen5_pip->resp_len) {
2576 			*gen5_pip->resp_len = (*gen5_pip->resp_len < length) ?
2577 				*gen5_pip->resp_len : length;
2578 			memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf,
2579 				*gen5_pip->resp_len);
2580 		}
2581 		atomic_dec(&gen5_pip->cmd_issued);
2582 		complete(&gen5_pip->cmd_ready);
2583 		return false;
2584 	}
2585 
2586 	return true;
2587 }
2588 
2589 static void cyapa_gen5_report_buttons(struct cyapa *cyapa,
2590 		const struct cyapa_gen5_report_data *report_data)
2591 {
2592 	struct input_dev *input = cyapa->input;
2593 	u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET];
2594 
2595 	buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
2596 
2597 	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
2598 		input_report_key(input, BTN_LEFT,
2599 			!!(buttons & CAPABILITY_LEFT_BTN_MASK));
2600 	}
2601 	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
2602 		input_report_key(input, BTN_MIDDLE,
2603 			!!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
2604 	}
2605 	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
2606 		input_report_key(input, BTN_RIGHT,
2607 			!!(buttons & CAPABILITY_RIGHT_BTN_MASK));
2608 	}
2609 
2610 	input_sync(input);
2611 }
2612 
2613 static void cyapa_gen5_report_slot_data(struct cyapa *cyapa,
2614 		const struct cyapa_gen5_touch_record *touch)
2615 {
2616 	struct input_dev *input = cyapa->input;
2617 	u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id);
2618 	int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id);
2619 	int x, y;
2620 
2621 	if (event_id == RECORD_EVENT_LIFTOFF)
2622 		return;
2623 
2624 	input_mt_slot(input, slot);
2625 	input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
2626 	x = (touch->x_hi << 8) | touch->x_lo;
2627 	if (cyapa->x_origin)
2628 		x = cyapa->max_abs_x - x;
2629 	input_report_abs(input, ABS_MT_POSITION_X, x);
2630 	y = (touch->y_hi << 8) | touch->y_lo;
2631 	if (cyapa->y_origin)
2632 		y = cyapa->max_abs_y - y;
2633 	input_report_abs(input, ABS_MT_POSITION_Y, y);
2634 	input_report_abs(input, ABS_MT_PRESSURE,
2635 		touch->z);
2636 	input_report_abs(input, ABS_MT_TOUCH_MAJOR,
2637 		touch->major_axis_len);
2638 	input_report_abs(input, ABS_MT_TOUCH_MINOR,
2639 		touch->minor_axis_len);
2640 
2641 	input_report_abs(input, ABS_MT_WIDTH_MAJOR,
2642 		touch->major_tool_len);
2643 	input_report_abs(input, ABS_MT_WIDTH_MINOR,
2644 		touch->minor_tool_len);
2645 
2646 	input_report_abs(input, ABS_MT_ORIENTATION,
2647 		touch->orientation);
2648 }
2649 
2650 static void cyapa_gen5_report_touches(struct cyapa *cyapa,
2651 		const struct cyapa_gen5_report_data *report_data)
2652 {
2653 	struct input_dev *input = cyapa->input;
2654 	unsigned int touch_num;
2655 	int i;
2656 
2657 	touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] &
2658 			GEN5_NUMBER_OF_TOUCH_MASK;
2659 
2660 	for (i = 0; i < touch_num; i++)
2661 		cyapa_gen5_report_slot_data(cyapa,
2662 			&report_data->touch_records[i]);
2663 
2664 	input_mt_sync_frame(input);
2665 	input_sync(input);
2666 }
2667 
2668 static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
2669 {
2670 	struct device *dev = &cyapa->client->dev;
2671 	struct cyapa_gen5_report_data report_data;
2672 	int ret;
2673 	u8 report_id;
2674 	unsigned int report_len;
2675 
2676 	if (cyapa->gen != CYAPA_GEN5 ||
2677 		cyapa->state != CYAPA_STATE_GEN5_APP) {
2678 		dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
2679 			cyapa->gen, cyapa->state);
2680 		return -EINVAL;
2681 	}
2682 
2683 	ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
2684 			GEN5_RESP_LENGTH_SIZE);
2685 	if (ret != GEN5_RESP_LENGTH_SIZE) {
2686 		dev_err(dev, "failed to read length bytes, (%d)\n", ret);
2687 		return -EINVAL;
2688 	}
2689 
2690 	report_len = get_unaligned_le16(
2691 			&report_data.report_head[GEN5_RESP_LENGTH_OFFSET]);
2692 	if (report_len < GEN5_RESP_LENGTH_SIZE) {
2693 		/* Invliad length or internal reset happened. */
2694 		dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
2695 			report_len, report_data.report_head[0],
2696 			report_data.report_head[1]);
2697 		return -EINVAL;
2698 	}
2699 
2700 	/* Idle, no data for report. */
2701 	if (report_len == GEN5_RESP_LENGTH_SIZE)
2702 		return 0;
2703 
2704 	ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
2705 	if (ret != report_len) {
2706 		dev_err(dev, "failed to read %d bytes report data, (%d)\n",
2707 			report_len, ret);
2708 		return -EINVAL;
2709 	}
2710 
2711 	report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET];
2712 	if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID &&
2713 			report_len == GEN5_WAKEUP_EVENT_SIZE) {
2714 		/*
2715 		 * Device wake event from deep sleep mode for touch.
2716 		 * This interrupt event is used to wake system up.
2717 		 */
2718 		return 0;
2719 	} else if (report_id != GEN5_TOUCH_REPORT_ID &&
2720 			report_id != GEN5_BTN_REPORT_ID &&
2721 			report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
2722 			report_id != GEN5_PUSH_BTN_REPORT_ID) {
2723 		/* Running in BL mode or unknown response data read. */
2724 		dev_err(dev, "invalid report_id=0x%02x\n", report_id);
2725 		return -EINVAL;
2726 	}
2727 
2728 	if (report_id == GEN5_TOUCH_REPORT_ID &&
2729 		(report_len < GEN5_TOUCH_REPORT_HEAD_SIZE ||
2730 			report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) {
2731 		/* Invalid report data length for finger packet. */
2732 		dev_err(dev, "invalid touch packet length=%d\n", report_len);
2733 		return 0;
2734 	}
2735 
2736 	if ((report_id == GEN5_BTN_REPORT_ID ||
2737 			report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
2738 			report_id == GEN5_PUSH_BTN_REPORT_ID) &&
2739 		(report_len < GEN5_BTN_REPORT_HEAD_SIZE ||
2740 			report_len > GEN5_BTN_REPORT_MAX_SIZE)) {
2741 		/* Invalid report data length of button packet. */
2742 		dev_err(dev, "invalid button packet length=%d\n", report_len);
2743 		return 0;
2744 	}
2745 
2746 	if (report_id == GEN5_TOUCH_REPORT_ID)
2747 		cyapa_gen5_report_touches(cyapa, &report_data);
2748 	else
2749 		cyapa_gen5_report_buttons(cyapa, &report_data);
2750 
2751 	return 0;
2752 }
2753 
2754 static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; }
2755 static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; }
2756 
2757 const struct cyapa_dev_ops cyapa_gen5_ops = {
2758 	.check_fw = cyapa_gen5_check_fw,
2759 	.bl_enter = cyapa_gen5_bl_enter,
2760 	.bl_initiate = cyapa_gen5_bl_initiate,
2761 	.update_fw = cyapa_gen5_do_fw_update,
2762 	.bl_activate = cyapa_gen5_bl_activate,
2763 	.bl_deactivate = cyapa_gen5_bl_deactivate,
2764 
2765 	.show_baseline = cyapa_gen5_show_baseline,
2766 	.calibrate_store = cyapa_gen5_do_calibrate,
2767 
2768 	.initialize = cyapa_gen5_initialize,
2769 
2770 	.state_parse = cyapa_gen5_state_parse,
2771 	.operational_check = cyapa_gen5_do_operational_check,
2772 
2773 	.irq_handler = cyapa_gen5_irq_handler,
2774 	.irq_cmd_handler = cyapa_gen5_irq_cmd_handler,
2775 	.sort_empty_output_data = cyapa_empty_pip_output_data,
2776 	.set_power_mode = cyapa_gen5_set_power_mode,
2777 };
2778