2 * Cypress APA trackpad with I2C interface
4 * Author: Dudley Du <dudl@cypress.com>
6 * Copyright (C) 2014 Cypress Semiconductor, Inc.
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
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>
26 #define RECORD_EVENT_NONE 0
27 #define RECORD_EVENT_TOUCHDOWN 1
28 #define RECORD_EVENT_DISPLACE 2
29 #define RECORD_EVENT_LIFTOFF 3
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
45 #define CYAPA_TSG_MAX_CMD_SIZE 256
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
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
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
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
71 #define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0
72 #define GEN5_DEEP_SLEEP_RESP_LENGTH 5
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
83 #define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08
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
92 #define GEN5_DEEP_SLEEP_STATE_MASK 0x03
93 #define GEN5_DEEP_SLEEP_STATE_ON 0x00
94 #define GEN5_DEEP_SLEEP_STATE_OFF 0x01
96 #define GEN5_DEEP_SLEEP_OPCODE 0x08
97 #define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
99 #define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */
100 #define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */
102 #define GEN5_CMD_REPORT_ID_OFFSET 4
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)
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)))
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
124 #define GEN5_RESP_LENGTH_OFFSET 0x00
125 #define GEN5_RESP_LENGTH_SIZE 2
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
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
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
145 #define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
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
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
162 #define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
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
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
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)
184 #define GEN5_PRODUCT_FAMILY_MASK 0xf000
185 #define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000
187 #define TSG_INVALID_CMD 0xff
189 struct cyapa_gen5_touch_record
{
191 * Bit 7 - 3: reserved
192 * Bit 2 - 0: touch type;
193 * 0 : standard finger;
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
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.
210 u8 touch_tip_event_id
;
212 /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
215 /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
218 /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
221 /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
224 /* Touch intensity in counts, pressure value. */
228 * The length of the major axis of the ellipse of contact between
229 * the finger and the panel (ABS_MT_TOUCH_MAJOR).
234 * The length of the minor axis of the ellipse of contact between
235 * the finger and the panel (ABS_MT_TOUCH_MINOR).
240 * The length of the major axis of the approaching tool.
241 * (ABS_MT_WIDTH_MAJOR)
246 * The length of the minor axis of the approaching tool.
247 * (ABS_MT_WIDTH_MINOR)
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.
263 struct cyapa_gen5_report_data
{
264 u8 report_head
[GEN5_TOUCH_REPORT_HEAD_SIZE
];
265 struct cyapa_gen5_touch_record touch_records
[10];
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. */
274 u8 fw_revision_control_number
[8];
277 struct cyapa_tsg_bin_image_data_record
{
280 /* The number of bytes of flash data contained in this record. */
282 /* The flash program data. */
283 u8 record_data
[CYAPA_TSG_FW_ROW_SIZE
];
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];
291 struct gen5_bl_packet_start
{
292 u8 sop
; /* Start of packet, must be 01h */
294 __le16 data_length
; /* Size of data parameter start from data[0] */
297 struct gen5_bl_packet_end
{
299 u8 eop
; /* End of packet, must be 17h */
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 */
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 */
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
];
320 struct gen5_bl_metadata_row_params
{
327 __le32 upgrade_start
;
329 __le16 entry_row_crc
;
330 u8 padding
[36]; /* Padding data must be 0 */
331 __le16 metadata_crc
; /* CRC starts at offset of 60 */
334 /* Bootload program and verify row command data structure */
335 struct gen5_bl_flash_row_head
{
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 */
345 u8 report_id
; /* Application output report id, must be 2Fh */
346 u8 rsvd
; /* Reserved, must be 0 */
348 * Bit 7: reserved, must be 0.
349 * Bit 6-0: command code.
352 u8 parameter_data
[0]; /* Parameter data variable based on cmd_code */
355 /* Application get/set parameter command data structure */
356 struct gen5_app_set_parameter_data
{
362 struct gen5_app_get_parameter_data
{
366 struct gen5_retrieve_panel_scan_data
{
368 __le16 read_elements
;
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)
381 static u8 cyapa_gen5_bl_cmd_key
[] = { 0xa5, 0x01, 0x02, 0x03,
382 0xff, 0xfe, 0xfd, 0x5a };
384 static int cyapa_gen5_initialize(struct cyapa
*cyapa
)
386 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
388 init_completion(&gen5_pip
->cmd_ready
);
389 atomic_set(&gen5_pip
->cmd_issued
, 0);
390 mutex_init(&gen5_pip
->cmd_lock
);
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
;
397 cyapa
->dev_pwr_mode
= UNINIT_PWR_MODE
;
398 cyapa
->dev_sleep_time
= UNINIT_SLEEP_TIME
;
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
)
411 if (!buf
|| size
> CYAPA_REG_MAP_SIZE
)
414 ret
= i2c_master_recv(cyapa
->client
, buf
, size
);
417 return (ret
< 0) ? ret
: -EIO
;
423 * Return a negative errno code else zero on success.
425 static ssize_t
cyapa_i2c_pip_write(struct cyapa
*cyapa
, u8
*buf
, size_t size
)
432 ret
= i2c_master_send(cyapa
->client
, buf
, size
);
435 return (ret
< 0) ? ret
: -EIO
;
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.
444 static int cyapa_empty_pip_output_data(struct cyapa
*cyapa
,
445 u8
*buf
, int *len
, cb_sort func
)
447 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
456 buf_len
= (*len
< CYAPA_REG_MAP_SIZE
) ?
457 *len
: CYAPA_REG_MAP_SIZE
;
461 report_count
= 8; /* max 7 pending data before command response data */
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.
479 error
= cyapa_i2c_pip_read(cyapa
, gen5_pip
->empty_buf
,
480 GEN5_RESP_LENGTH_SIZE
);
484 length
= get_unaligned_le16(gen5_pip
->empty_buf
);
485 if (length
== GEN5_RESP_LENGTH_SIZE
) {
488 } else if (length
> CYAPA_REG_MAP_SIZE
) {
489 /* Should not happen */
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
);
499 /* Response found, success. */
505 error
= cyapa_i2c_pip_read(cyapa
, gen5_pip
->empty_buf
, length
);
511 length
= get_unaligned_le16(gen5_pip
->empty_buf
);
512 if (length
<= GEN5_RESP_LENGTH_SIZE
) {
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
);
519 /* Response found, success. */
524 } while (report_count
);
529 static int cyapa_do_i2c_pip_cmd_irq_sync(
531 u8
*cmd
, size_t cmd_len
,
532 unsigned long timeout
)
534 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
537 /* Wait for interrupt to set ready completion */
538 init_completion(&gen5_pip
->cmd_ready
);
540 atomic_inc(&gen5_pip
->cmd_issued
);
541 error
= cyapa_i2c_pip_write(cyapa
, cmd
, cmd_len
);
543 atomic_dec(&gen5_pip
->cmd_issued
);
544 return (error
< 0) ? error
: -EIO
;
547 /* Wait for interrupt to indicate command is completed. */
548 timeout
= wait_for_completion_timeout(&gen5_pip
->cmd_ready
,
549 msecs_to_jiffies(timeout
));
551 atomic_dec(&gen5_pip
->cmd_issued
);
558 static int cyapa_do_i2c_pip_cmd_polling(
560 u8
*cmd
, size_t cmd_len
,
561 u8
*resp_data
, int *resp_len
,
562 unsigned long timeout
,
565 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
570 atomic_inc(&gen5_pip
->cmd_issued
);
571 error
= cyapa_i2c_pip_write(cyapa
, cmd
, cmd_len
);
573 atomic_dec(&gen5_pip
->cmd_issued
);
574 return error
< 0 ? error
: -EIO
;
577 length
= resp_len
? *resp_len
: 0;
578 if (resp_data
&& resp_len
&& length
!= 0 && func
) {
581 usleep_range(3000, 5000);
583 error
= cyapa_empty_pip_output_data(cyapa
,
584 resp_data
, resp_len
, func
);
585 if (error
|| *resp_len
== 0)
589 } while (--tries
> 0);
590 if ((error
|| *resp_len
== 0) || tries
<= 0)
591 error
= error
? error
: -ETIMEDOUT
;
594 atomic_dec(&gen5_pip
->cmd_issued
);
598 static int cyapa_i2c_pip_cmd_irq_sync(
600 u8
*cmd
, int cmd_len
,
601 u8
*resp_data
, int *resp_len
,
602 unsigned long timeout
,
606 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
609 if (!cmd
|| !cmd_len
)
612 /* Commands must be serialized. */
613 error
= mutex_lock_interruptible(&gen5_pip
->cmd_lock
);
617 gen5_pip
->resp_sort_func
= func
;
618 gen5_pip
->resp_data
= resp_data
;
619 gen5_pip
->resp_len
= resp_len
;
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];
631 /* Send command data, wait and read output response data's length. */
633 gen5_pip
->is_irq_mode
= true;
634 error
= cyapa_do_i2c_pip_cmd_irq_sync(cyapa
, cmd
, cmd_len
,
636 if (error
== -ETIMEDOUT
&& resp_data
&&
637 resp_len
&& *resp_len
!= 0 && func
) {
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.
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
;
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
);
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
;
659 mutex_unlock(&gen5_pip
->cmd_lock
);
663 static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa
*cyapa
,
666 if (!data
|| len
< GEN5_MIN_BL_RESP_LENGTH
)
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
)
678 static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa
*cyapa
,
681 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
684 if (!data
|| len
< GEN5_MIN_APP_RESP_LENGTH
)
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 */
695 } else if (GET_GEN5_CMD_CODE(data
[GEN5_RESP_APP_CMD_OFFSET
]) ==
696 gen5_pip
->in_progress_cmd
) {
697 /* Correct command response received */
705 static bool cyapa_gen5_sort_application_launch_data(struct cyapa
*cyapa
,
708 if (buf
== NULL
|| len
< GEN5_RESP_LENGTH_SIZE
)
712 * After reset or power on, trackpad device always sets to 0x00 0x00
713 * to indicate a reset or power on event.
715 if (buf
[0] == 0 && buf
[1] == 0)
721 static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa
*cyapa
,
727 /* Check hid descriptor. */
728 if (len
!= GEN5_HID_DESCRIPTOR_SIZE
)
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 */
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 */
749 static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa
*cyapa
,
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
)
761 static int gen5_idle_state_parse(struct cyapa
*cyapa
)
763 u8 resp_data
[GEN5_HID_DESCRIPTOR_SIZE
];
771 * Dump all buffered data firstly for the situation
772 * when the trackpad is just power on the cyapa go here.
774 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
776 memset(resp_data
, 0, sizeof(resp_data
));
777 ret
= cyapa_i2c_pip_read(cyapa
, resp_data
, 3);
779 return ret
< 0 ? ret
: -EIO
;
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
;
786 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
788 /* Read description from trackpad device */
791 length
= GEN5_HID_DESCRIPTOR_SIZE
;
792 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
793 cmd
, GEN5_RESP_LENGTH_SIZE
,
796 cyapa_gen5_sort_hid_descriptor_data
,
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
;
819 /* Should not happen!!! */
820 cyapa
->state
= CYAPA_STATE_NO_DEVICE
;
827 static int gen5_hid_description_header_parse(struct cyapa
*cyapa
, u8
*reg_data
)
834 /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
835 * 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
837 * Must read HID Description content through out,
838 * otherwise Gen5 trackpad cannot response next command
839 * or report any touch or button data.
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
) {
851 * BL mode HID Description has been previously
854 cyapa
->gen
= CYAPA_GEN5
;
855 cyapa
->state
= CYAPA_STATE_GEN5_BL
;
858 * APP mode HID Description has been previously
861 cyapa
->gen
= CYAPA_GEN5
;
862 cyapa
->state
= CYAPA_STATE_GEN5_APP
;
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
;
878 /* Should not happen!!! */
879 cyapa
->state
= CYAPA_STATE_NO_DEVICE
;
885 static int gen5_report_data_header_parse(struct cyapa
*cyapa
, u8
*reg_data
)
889 length
= get_unaligned_le16(®_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
)
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
)
903 case GEN5_WAKEUP_EVENT_REPORT_ID
:
904 if (length
!= GEN5_WAKEUP_EVENT_SIZE
)
911 cyapa
->gen
= CYAPA_GEN5
;
912 cyapa
->state
= CYAPA_STATE_GEN5_APP
;
916 static int gen5_cmd_resp_header_parse(struct cyapa
*cyapa
, u8
*reg_data
)
918 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
923 * Must read report data through out,
924 * otherwise Gen5 trackpad cannot response next command
925 * or report any touch or button data.
927 length
= get_unaligned_le16(®_data
[GEN5_RESP_LENGTH_OFFSET
]);
928 ret
= cyapa_i2c_pip_read(cyapa
, gen5_pip
->empty_buf
, length
);
930 return ret
< 0 ? ret
: -EIO
;
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
;
940 /* Gen5 APP command response data detected */
941 cyapa
->gen
= CYAPA_GEN5
;
942 cyapa
->state
= CYAPA_STATE_GEN5_APP
;
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
] ==
950 (gen5_pip
->empty_buf
[length
- 1] ==
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
;
963 /* Should not happen!!! */
964 cyapa
->state
= CYAPA_STATE_NO_DEVICE
;
970 static int cyapa_gen5_state_parse(struct cyapa
*cyapa
, u8
*reg_data
, int len
)
974 if (!reg_data
|| len
< 3)
977 cyapa
->state
= CYAPA_STATE_NO_DEVICE
;
979 /* Parse based on Gen5 characteristic registers and bits */
980 length
= get_unaligned_le16(®_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
);
1009 if (cyapa
->gen
== CYAPA_GEN5
) {
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.
1016 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1018 if (cyapa
->state
== CYAPA_STATE_GEN5_APP
||
1019 cyapa
->state
== CYAPA_STATE_GEN5_BL
)
1026 static int cyapa_gen5_bl_initiate(struct cyapa
*cyapa
,
1027 const struct firmware
*fw
)
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
];
1038 u16 meta_data_crc
= 0;
1045 /* Try to dump all buffered report data before any send command. */
1046 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
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
);
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
;
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
);
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
);
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
);
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
);
1080 bl_packet_end
= (struct gen5_bl_packet_end
*)(bl_cmd_head
->data
+
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
;
1087 resp_len
= sizeof(resp_data
);
1088 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
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
;
1100 static bool cyapa_gen5_sort_bl_exit_data(struct cyapa
*cyapa
, u8
*buf
, int len
)
1102 if (buf
== NULL
|| len
< GEN5_RESP_LENGTH_SIZE
)
1105 if (buf
[0] == 0 && buf
[1] == 0)
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
)
1120 static int cyapa_gen5_bl_exit(struct cyapa
*cyapa
)
1123 u8 bl_gen5_bl_exit
[] = { 0x04, 0x00,
1124 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
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);
1139 if (resp_len
== GEN5_BL_FAIL_EXIT_RESP_LEN
||
1140 resp_data
[GEN5_RESP_REPORT_ID_OFFSET
] ==
1141 GEN5_BL_RESP_REPORT_ID
)
1144 if (resp_data
[0] == 0x00 && resp_data
[1] == 0x00)
1150 static int cyapa_gen5_bl_enter(struct cyapa
*cyapa
)
1152 u8 cmd
[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
1157 error
= cyapa_poll_state(cyapa
, 500);
1160 if (cyapa
->gen
!= CYAPA_GEN5
)
1163 /* Already in Gen5 BL. Skipping exit. */
1164 if (cyapa
->state
== CYAPA_STATE_GEN5_BL
)
1167 if (cyapa
->state
!= CYAPA_STATE_GEN5_APP
)
1170 /* Try to dump all buffered report data before any send command. */
1171 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1174 * Send bootloader enter command to trackpad device,
1175 * after enter bootloader, the response data is two bytes of 0x00 0x00.
1177 resp_len
= sizeof(resp_data
);
1178 memset(resp_data
, 0, resp_len
);
1179 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
1181 resp_data
, &resp_len
,
1182 5000, cyapa_gen5_sort_application_launch_data
,
1184 if (error
|| resp_data
[0] != 0x00 || resp_data
[1] != 0x00)
1185 return error
< 0 ? error
: -EAGAIN
;
1187 cyapa
->operational
= false;
1188 cyapa
->state
= CYAPA_STATE_GEN5_BL
;
1192 static int cyapa_gen5_check_fw(struct cyapa
*cyapa
, const struct firmware
*fw
)
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
;
1202 u16 app_integrity_crc
;
1206 flash_records_count
= (fw
->size
-
1207 sizeof(struct cyapa_tsg_bin_image_head
)) /
1208 sizeof(struct cyapa_tsg_bin_image_data_record
);
1211 * APP_INTEGRITY row is always the last row block,
1212 * and the row id must be 0x01ff.
1214 app_integrity
= &image
->records
[flash_records_count
- 1];
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__
);
1222 metadata
= (const void *)app_integrity
->record_data
;
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__
);
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
);
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__
);
1246 * Verify application image CRC
1248 record_index
= fw_app_start
/ CYAPA_TSG_FW_ROW_SIZE
-
1249 CYAPA_TSG_IMG_START_ROW_NUM
;
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
);
1256 if (app_crc
!= get_unaligned_le16(&metadata
->app_crc
)) {
1257 dev_err(dev
, "%s: invalid firmware app crc check.\n", __func__
);
1264 static int cyapa_gen5_write_fw_block(struct cyapa
*cyapa
,
1265 struct cyapa_tsg_bin_image_data_record
*flash_record
)
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
];
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
;
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
);
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
;
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
);
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
);
1312 bl_packet_end
= (struct gen5_bl_packet_end
*)(bl_cmd_head
->data
+
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
;
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
;
1331 static int cyapa_gen5_do_fw_update(struct cyapa
*cyapa
,
1332 const struct firmware
*fw
)
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
;
1342 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1344 flash_records_count
=
1345 (fw
->size
- sizeof(struct cyapa_tsg_bin_image_head
)) /
1346 sizeof(struct cyapa_tsg_bin_image_data_record
);
1348 * The last flash row 0x01ff has been written through bl_initiate
1349 * command, so DO NOT write flash 0x01ff to trackpad device.
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
);
1355 dev_err(dev
, "%s: Gen5 FW update aborted: %d\n",
1364 static int cyapa_gen5_change_power_state(struct cyapa
*cyapa
, u8 power_state
)
1366 u8 cmd
[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
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
;
1383 static int cyapa_gen5_set_interval_time(struct cyapa
*cyapa
,
1384 u8 parameter_id
, u16 interval_time
)
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
];
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
);
1402 switch (parameter_id
) {
1403 case GEN5_PARAMETER_ACT_INTERVL_ID
:
1404 parameter_size
= GEN5_PARAMETER_ACT_INTERVL_SIZE
;
1406 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID
:
1407 parameter_size
= GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE
;
1409 case GEN5_PARAMETER_LP_INTRVL_ID
:
1410 parameter_size
= GEN5_PARAMETER_LP_INTRVL_SIZE
;
1416 put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR
, &app_cmd_head
->addr
);
1418 * Don't include unused parameter value bytes and
1419 * 2 bytes register address.
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
, ¶meter_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
;
1440 static int cyapa_gen5_get_interval_time(struct cyapa
*cyapa
,
1441 u8 parameter_id
, u16
*interval_time
)
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
];
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
);
1461 switch (parameter_id
) {
1462 case GEN5_PARAMETER_ACT_INTERVL_ID
:
1463 parameter_size
= GEN5_PARAMETER_ACT_INTERVL_SIZE
;
1465 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID
:
1466 parameter_size
= GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE
;
1468 case GEN5_PARAMETER_LP_INTRVL_ID
:
1469 parameter_size
= GEN5_PARAMETER_LP_INTRVL_SIZE
;
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
;
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
;
1491 for (i
= 0; i
< parameter_size
; i
++)
1492 mask
|= (0xff << (i
* 8));
1493 *interval_time
= get_unaligned_le16(&resp_data
[7]) & mask
;
1498 static int cyapa_gen5_disable_pip_report(struct cyapa
*cyapa
)
1500 struct gen5_app_cmd_head
*app_cmd_head
;
1506 memset(cmd
, 0, sizeof(cmd
));
1507 app_cmd_head
= (struct gen5_app_cmd_head
*)cmd
;
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
;
1528 static int cyapa_gen5_deep_sleep(struct cyapa
*cyapa
, u8 state
)
1530 u8 cmd
[] = { 0x05, 0x00, 0x00, 0x08};
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
))
1546 static int cyapa_gen5_set_power_mode(struct cyapa
*cyapa
,
1547 u8 power_mode
, u16 sleep_time
)
1549 struct device
*dev
= &cyapa
->client
->dev
;
1553 if (cyapa
->state
!= CYAPA_STATE_GEN5_APP
)
1556 /* Dump all the report data before do power mode commmands. */
1557 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1559 if (GEN5_DEV_GET_PWR_STATE(cyapa
) == UNINIT_PWR_MODE
) {
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.
1565 GEN5_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_OFF
);
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
);
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. */
1585 if (power_mode
== PWR_MODE_OFF
) {
1586 error
= cyapa_gen5_deep_sleep(cyapa
, GEN5_DEEP_SLEEP_STATE_OFF
);
1588 dev_err(dev
, "enter deep sleep fail: %d\n", error
);
1592 GEN5_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_OFF
);
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.
1601 if (GEN5_DEV_GET_PWR_STATE(cyapa
) == PWR_MODE_OFF
) {
1602 error
= cyapa_gen5_deep_sleep(cyapa
, GEN5_DEEP_SLEEP_STATE_ON
);
1604 dev_err(dev
, "deep sleep wake fail: %d\n", error
);
1609 if (power_mode
== PWR_MODE_FULL_ACTIVE
) {
1610 error
= cyapa_gen5_change_power_state(cyapa
,
1611 GEN5_POWER_STATE_ACTIVE
);
1613 dev_err(dev
, "change to active fail: %d\n", error
);
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
);
1622 dev_err(dev
, "fail to button only mode: %d\n", error
);
1626 GEN5_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_BTN_ONLY
);
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.
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
,
1638 GEN5_DEV_SET_SLEEP_TIME(cyapa
, sleep_time
);
1640 if (sleep_time
<= GEN5_POWER_READY_MAX_INTRVL_TIME
)
1641 power_state
= GEN5_POWER_STATE_READY
;
1643 power_state
= GEN5_POWER_STATE_IDLE
;
1644 error
= cyapa_gen5_change_power_state(cyapa
, power_state
);
1646 dev_err(dev
, "set power state to 0x%02x failed: %d\n",
1647 power_state
, error
);
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 buffered when system
1658 * is suspending which may cause interrupt line unable to be
1661 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1662 cyapa_gen5_disable_pip_report(cyapa
);
1664 GEN5_DEV_SET_PWR_STATE(cyapa
,
1665 cyapa_sleep_time_to_pwr_cmd(sleep_time
));
1671 static int cyapa_gen5_resume_scanning(struct cyapa
*cyapa
)
1673 u8 cmd
[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
1678 /* Try to dump all buffered data before doing command. */
1679 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1681 resp_len
= sizeof(resp_data
);
1682 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
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))
1689 /* Try to dump all buffered data when resuming scanning. */
1690 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1695 static int cyapa_gen5_suspend_scanning(struct cyapa
*cyapa
)
1697 u8 cmd
[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
1702 /* Try to dump all buffered data before doing command. */
1703 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1705 resp_len
= sizeof(resp_data
);
1706 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
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))
1713 /* Try to dump all buffered data when suspending scanning. */
1714 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
1719 static int cyapa_gen5_calibrate_pwcs(struct cyapa
*cyapa
,
1720 u8 calibrate_sensing_mode_type
)
1722 struct gen5_app_cmd_head
*app_cmd_head
;
1728 /* Try to dump all buffered data before doing command. */
1729 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
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
,
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
;
1750 static ssize_t
cyapa_gen5_do_calibrate(struct device
*dev
,
1751 struct device_attribute
*attr
,
1752 const char *buf
, size_t count
)
1754 struct cyapa
*cyapa
= dev_get_drvdata(dev
);
1755 int error
, calibrate_error
;
1757 /* 1. Suspend Scanning*/
1758 error
= cyapa_gen5_suspend_scanning(cyapa
);
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
;
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
;
1775 /* 4. Resume Scanning*/
1776 error
= cyapa_gen5_resume_scanning(cyapa
);
1777 if (error
|| calibrate_error
)
1778 return error
? error
: calibrate_error
;
1783 static s32
twos_complement_to_s32(s32 value
, int num_bits
)
1785 if (value
>> (num_bits
- 1))
1786 value
|= -1 << num_bits
;
1790 static s32
cyapa_parse_structure_data(u8 data_format
, u8
*buf
, int buf_len
)
1797 data_size
= (data_format
& 0x07);
1798 big_endian
= ((data_format
& 0x10) == 0x00);
1799 unsigned_type
= ((data_format
& 0x20) == 0x00);
1801 if (buf_len
< data_size
)
1804 switch (data_size
) {
1810 value
= get_unaligned_be16(buf
);
1812 value
= get_unaligned_le16(buf
);
1816 value
= get_unaligned_be32(buf
);
1818 value
= get_unaligned_le32(buf
);
1821 /* Should not happen, just as default case here. */
1827 value
= twos_complement_to_s32(value
, data_size
* 8);
1832 static void cyapa_gen5_guess_electrodes(struct cyapa
*cyapa
,
1833 int *electrodes_rx
, int *electrodes_tx
)
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
;
1840 *electrodes_tx
= min(cyapa
->electrodes_x
, cyapa
->electrodes_y
);
1841 *electrodes_rx
= max(cyapa
->electrodes_x
, cyapa
->electrodes_y
);
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
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.
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
)
1867 struct gen5_app_cmd_head
*cmd_head
;
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
;
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
)
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) {
1894 * Read global idac values firstly.
1895 * Currently, no idac data exceed 4 bytes.
1897 read_global_idac
= true;
1902 tmp_ave
= tmp_sum
= tmp_count
= 0;
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;
1912 (cyapa
->aligned_electrodes_rx
+ 7) & ~7u;
1914 max_element_cnt
= 2;
1917 read_global_idac
= false;
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
;
1926 electrodes_tx
= cyapa
->electrodes_x
;
1927 max_element_cnt
= ((cyapa
->aligned_electrodes_rx
+ 7) &
1928 ~7u) * electrodes_tx
;
1931 max_element_cnt
= cyapa
->electrodes_x
+
1932 cyapa
->electrodes_y
;
1933 max_element_cnt
= (max_element_cnt
+ 3) & ~3u;
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
;
1944 read_elements
= (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET
) /
1946 read_elements
= min(read_elements
, max_element_cnt
- count
);
1947 read_len
= read_elements
* (*data_size
);
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
,
1955 resp_data
, &resp_len
,
1956 500, cyapa_gen5_sort_tsg_pip_app_resp_data
,
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]);
1967 *data_size
= (resp_data
[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK
);
1968 if (read_len
< *data_size
)
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(
1976 &resp_data
[GEN5_RESP_DATA_STRUCTURE_OFFSET
],
1978 /* Tx's self global idac data. */
1979 *idac_min
= cyapa_parse_structure_data(
1981 &resp_data
[GEN5_RESP_DATA_STRUCTURE_OFFSET
+
1987 /* Read mutual global idac or local mutual/self PWC data. */
1989 for (i
= 10; i
< (read_len
+ GEN5_RESP_DATA_STRUCTURE_OFFSET
);
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
);
1996 if (idac_data_type
== GEN5_RETRIEVE_MUTUAL_PWC_DATA
&&
1997 tmp_count
< cyapa
->aligned_electrodes_rx
&&
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.
2005 if (!tmp_ave
|| value
> tmp_ave
/ 2) {
2006 tmp_min
= min(value
, tmp_min
);
2007 tmp_max
= max(value
, tmp_max
);
2011 tmp_ave
= tmp_sum
/ tmp_count
;
2018 if (count
>= max_element_cnt
)
2024 *idac_ave
= count
? (sum
/ count
) : 0;
2026 if (read_global_idac
&&
2027 idac_data_type
== GEN5_RETRIEVE_MUTUAL_PWC_DATA
) {
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
;
2039 cyapa
->electrodes_rx
= cyapa
->electrodes_rx
?
2040 cyapa
->electrodes_rx
: electrodes_tx
;
2041 cyapa
->aligned_electrodes_rx
= tmp_count
;
2044 *idac_min
= tmp_min
;
2045 *idac_max
= tmp_max
;
2046 *idac_ave
= tmp_ave
;
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
)
2059 *gidac_mutual_max
= *gidac_mutual_min
= *gidac_mutual_ave
= 0;
2060 *lidac_mutual_max
= *lidac_mutual_min
= *lidac_mutual_ave
= 0;
2063 error
= cyapa_gen5_read_idac_data(cyapa
,
2064 GEN5_CMD_RETRIEVE_DATA_STRUCTURE
,
2065 GEN5_RETRIEVE_MUTUAL_PWC_DATA
,
2067 gidac_mutual_max
, gidac_mutual_min
, gidac_mutual_ave
);
2071 error
= cyapa_gen5_read_idac_data(cyapa
,
2072 GEN5_CMD_RETRIEVE_DATA_STRUCTURE
,
2073 GEN5_RETRIEVE_MUTUAL_PWC_DATA
,
2075 lidac_mutual_max
, lidac_mutual_min
, lidac_mutual_ave
);
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
)
2086 *gidac_self_rx
= *gidac_self_tx
= 0;
2087 *lidac_self_max
= *lidac_self_min
= *lidac_self_ave
= 0;
2090 error
= cyapa_gen5_read_idac_data(cyapa
,
2091 GEN5_CMD_RETRIEVE_DATA_STRUCTURE
,
2092 GEN5_RETRIEVE_SELF_CAP_PWC_DATA
,
2094 lidac_self_max
, lidac_self_min
, lidac_self_ave
);
2097 *gidac_self_rx
= *lidac_self_max
;
2098 *gidac_self_tx
= *lidac_self_min
;
2100 error
= cyapa_gen5_read_idac_data(cyapa
,
2101 GEN5_CMD_RETRIEVE_DATA_STRUCTURE
,
2102 GEN5_RETRIEVE_SELF_CAP_PWC_DATA
,
2104 lidac_self_max
, lidac_self_min
, lidac_self_ave
);
2108 static ssize_t
cyapa_gen5_execute_panel_scan(struct cyapa
*cyapa
)
2110 struct gen5_app_cmd_head
*app_cmd_head
;
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
,
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
;
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
,
2141 struct gen5_app_cmd_head
*app_cmd_head
;
2142 struct gen5_retrieve_panel_scan_data
*panel_sacn_data
;
2144 u8 resp_data
[256]; /* Max bytes can transfer one time. */
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
)
2161 intp
= (s32
*)buffer
;
2162 *raw_data_max
= INT_MIN
;
2163 *raw_data_min
= INT_MAX
;
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
;
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
;
2182 resp_len
= GEN5_RESP_DATA_STRUCTURE_OFFSET
+ read_len
;
2183 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
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
;
2193 read_elements
= get_unaligned_le16(&resp_data
[7]);
2194 if (read_elements
== 0)
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
);
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
);
2210 put_unaligned_le32(value
, &intp
[count
]);
2218 if (count
>= raw_data_max_num
)
2221 read_elements
= (sizeof(resp_data
) -
2222 GEN5_RESP_DATA_STRUCTURE_OFFSET
) / data_size
;
2223 read_len
= read_elements
* data_size
;
2226 *raw_data_ave
= count
? (sum
/ count
) : 0;
2231 static ssize_t
cyapa_gen5_show_baseline(struct device
*dev
,
2232 struct device_attribute
*attr
, char *buf
)
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
;
2248 if (cyapa
->state
!= CYAPA_STATE_GEN5_APP
)
2251 /* 1. Suspend Scanning*/
2252 error
= cyapa_gen5_suspend_scanning(cyapa
);
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
);
2263 goto resume_scanning
;
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
,
2271 goto resume_scanning
;
2273 /* 4. Execuate panel scan. It must be executed before read data. */
2274 error
= cyapa_gen5_execute_panel_scan(cyapa
);
2276 goto resume_scanning
;
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
,
2287 goto resume_scanning
;
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
,
2298 goto resume_scanning
;
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
,
2309 goto resume_scanning
;
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
,
2320 goto resume_scanning
;
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
,
2331 goto resume_scanning
;
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
,
2342 goto 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
;
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
);
2367 static bool cyapa_gen5_sort_system_info_data(struct cyapa
*cyapa
,
2370 /* Check the report id and command code */
2371 if (VALID_CMD_RESP_HEADER(buf
, 0x02))
2377 static int cyapa_gen5_bl_query_data(struct cyapa
*cyapa
)
2379 u8 bl_query_data_cmd
[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
2380 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
2382 u8 resp_data
[GEN5_BL_READ_APP_INFO_RESP_LEN
];
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
;
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';
2402 cyapa
->fw_maj_ver
= resp_data
[22];
2403 cyapa
->fw_min_ver
= resp_data
[23];
2408 static int cyapa_gen5_get_query_data(struct cyapa
*cyapa
)
2410 u8 get_system_information
[] = {
2411 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
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
;
2426 product_family
= get_unaligned_le16(&resp_data
[7]);
2427 if ((product_family
& GEN5_PRODUCT_FAMILY_MASK
) !=
2428 GEN5_PRODUCT_FAMILY_TRACKPAD
)
2431 cyapa
->fw_maj_ver
= resp_data
[15];
2432 cyapa
->fw_min_ver
= resp_data
[16];
2434 cyapa
->electrodes_x
= resp_data
[52];
2435 cyapa
->electrodes_y
= resp_data
[53];
2437 cyapa
->physical_size_x
= get_unaligned_le16(&resp_data
[54]) / 100;
2438 cyapa
->physical_size_y
= get_unaligned_le16(&resp_data
[56]) / 100;
2440 cyapa
->max_abs_x
= get_unaligned_le16(&resp_data
[58]);
2441 cyapa
->max_abs_y
= get_unaligned_le16(&resp_data
[60]);
2443 cyapa
->max_z
= get_unaligned_le16(&resp_data
[62]);
2445 cyapa
->x_origin
= resp_data
[64] & 0x01;
2446 cyapa
->y_origin
= resp_data
[65] & 0x01;
2448 cyapa
->btn_capability
= (resp_data
[70] << 3) & CAPABILITY_BTN_MASK
;
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';
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
)
2465 static int cyapa_gen5_do_operational_check(struct cyapa
*cyapa
)
2467 struct device
*dev
= &cyapa
->client
->dev
;
2470 if (cyapa
->gen
!= CYAPA_GEN5
)
2473 switch (cyapa
->state
) {
2474 case CYAPA_STATE_GEN5_BL
:
2475 error
= cyapa_gen5_bl_exit(cyapa
);
2477 /* Rry to update trackpad product information. */
2478 cyapa_gen5_bl_query_data(cyapa
);
2482 cyapa
->state
= CYAPA_STATE_GEN5_APP
;
2484 case CYAPA_STATE_GEN5_APP
:
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.
2491 error
= cyapa_gen5_set_power_mode(cyapa
,
2492 PWR_MODE_FULL_ACTIVE
, 0);
2494 dev_warn(dev
, "%s: failed to set power active mode.\n",
2497 /* Get trackpad product information. */
2498 error
= cyapa_gen5_get_query_data(cyapa
);
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
);
2518 * Return false, do not continue process
2519 * Return true, continue process.
2521 static bool cyapa_gen5_irq_cmd_handler(struct cyapa
*cyapa
)
2523 struct cyapa_gen5_cmd_states
*gen5_pip
= &cyapa
->cmd_states
.gen5
;
2526 if (atomic_read(&gen5_pip
->cmd_issued
)) {
2527 /* Polling command response data. */
2528 if (gen5_pip
->is_irq_mode
== false)
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.
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
);
2545 if (!(gen5_pip
->resp_sort_func
&&
2546 gen5_pip
->resp_sort_func(cyapa
,
2547 gen5_pip
->irq_cmd_buf
, length
))) {
2549 * Work around the Gen5 V1 firmware
2550 * that does not assert interrupt signalling
2551 * that command response is ready if user
2552 * keeps touching the trackpad while command
2553 * is sent to the device.
2556 if (gen5_pip
->resp_len
)
2557 length
= *gen5_pip
->resp_len
;
2558 cyapa_empty_pip_output_data(cyapa
,
2559 gen5_pip
->resp_data
,
2561 gen5_pip
->resp_sort_func
);
2562 if (gen5_pip
->resp_len
&& length
!= 0) {
2563 *gen5_pip
->resp_len
= length
;
2564 atomic_dec(&gen5_pip
->cmd_issued
);
2565 complete(&gen5_pip
->cmd_ready
);
2570 if (gen5_pip
->resp_data
&& gen5_pip
->resp_len
) {
2571 *gen5_pip
->resp_len
= (*gen5_pip
->resp_len
< length
) ?
2572 *gen5_pip
->resp_len
: length
;
2573 memcpy(gen5_pip
->resp_data
, gen5_pip
->irq_cmd_buf
,
2574 *gen5_pip
->resp_len
);
2576 atomic_dec(&gen5_pip
->cmd_issued
);
2577 complete(&gen5_pip
->cmd_ready
);
2584 static void cyapa_gen5_report_buttons(struct cyapa
*cyapa
,
2585 const struct cyapa_gen5_report_data
*report_data
)
2587 struct input_dev
*input
= cyapa
->input
;
2588 u8 buttons
= report_data
->report_head
[GEN5_BUTTONS_OFFSET
];
2590 buttons
= (buttons
<< CAPABILITY_BTN_SHIFT
) & CAPABILITY_BTN_MASK
;
2592 if (cyapa
->btn_capability
& CAPABILITY_LEFT_BTN_MASK
) {
2593 input_report_key(input
, BTN_LEFT
,
2594 !!(buttons
& CAPABILITY_LEFT_BTN_MASK
));
2596 if (cyapa
->btn_capability
& CAPABILITY_MIDDLE_BTN_MASK
) {
2597 input_report_key(input
, BTN_MIDDLE
,
2598 !!(buttons
& CAPABILITY_MIDDLE_BTN_MASK
));
2600 if (cyapa
->btn_capability
& CAPABILITY_RIGHT_BTN_MASK
) {
2601 input_report_key(input
, BTN_RIGHT
,
2602 !!(buttons
& CAPABILITY_RIGHT_BTN_MASK
));
2608 static void cyapa_gen5_report_slot_data(struct cyapa
*cyapa
,
2609 const struct cyapa_gen5_touch_record
*touch
)
2611 struct input_dev
*input
= cyapa
->input
;
2612 u8 event_id
= GEN5_GET_EVENT_ID(touch
->touch_tip_event_id
);
2613 int slot
= GEN5_GET_TOUCH_ID(touch
->touch_tip_event_id
);
2616 if (event_id
== RECORD_EVENT_LIFTOFF
)
2619 input_mt_slot(input
, slot
);
2620 input_mt_report_slot_state(input
, MT_TOOL_FINGER
, true);
2621 x
= (touch
->x_hi
<< 8) | touch
->x_lo
;
2622 if (cyapa
->x_origin
)
2623 x
= cyapa
->max_abs_x
- x
;
2624 input_report_abs(input
, ABS_MT_POSITION_X
, x
);
2625 y
= (touch
->y_hi
<< 8) | touch
->y_lo
;
2626 if (cyapa
->y_origin
)
2627 y
= cyapa
->max_abs_y
- y
;
2628 input_report_abs(input
, ABS_MT_POSITION_Y
, y
);
2629 input_report_abs(input
, ABS_MT_PRESSURE
,
2631 input_report_abs(input
, ABS_MT_TOUCH_MAJOR
,
2632 touch
->major_axis_len
);
2633 input_report_abs(input
, ABS_MT_TOUCH_MINOR
,
2634 touch
->minor_axis_len
);
2636 input_report_abs(input
, ABS_MT_WIDTH_MAJOR
,
2637 touch
->major_tool_len
);
2638 input_report_abs(input
, ABS_MT_WIDTH_MINOR
,
2639 touch
->minor_tool_len
);
2641 input_report_abs(input
, ABS_MT_ORIENTATION
,
2642 touch
->orientation
);
2645 static void cyapa_gen5_report_touches(struct cyapa
*cyapa
,
2646 const struct cyapa_gen5_report_data
*report_data
)
2648 struct input_dev
*input
= cyapa
->input
;
2649 unsigned int touch_num
;
2652 touch_num
= report_data
->report_head
[GEN5_NUMBER_OF_TOUCH_OFFSET
] &
2653 GEN5_NUMBER_OF_TOUCH_MASK
;
2655 for (i
= 0; i
< touch_num
; i
++)
2656 cyapa_gen5_report_slot_data(cyapa
,
2657 &report_data
->touch_records
[i
]);
2659 input_mt_sync_frame(input
);
2663 static int cyapa_gen5_irq_handler(struct cyapa
*cyapa
)
2665 struct device
*dev
= &cyapa
->client
->dev
;
2666 struct cyapa_gen5_report_data report_data
;
2669 unsigned int report_len
;
2671 if (cyapa
->gen
!= CYAPA_GEN5
||
2672 cyapa
->state
!= CYAPA_STATE_GEN5_APP
) {
2673 dev_err(dev
, "invalid device state, gen=%d, state=0x%02x\n",
2674 cyapa
->gen
, cyapa
->state
);
2678 ret
= cyapa_i2c_pip_read(cyapa
, (u8
*)&report_data
,
2679 GEN5_RESP_LENGTH_SIZE
);
2680 if (ret
!= GEN5_RESP_LENGTH_SIZE
) {
2681 dev_err(dev
, "failed to read length bytes, (%d)\n", ret
);
2685 report_len
= get_unaligned_le16(
2686 &report_data
.report_head
[GEN5_RESP_LENGTH_OFFSET
]);
2687 if (report_len
< GEN5_RESP_LENGTH_SIZE
) {
2688 /* Invliad length or internal reset happened. */
2689 dev_err(dev
, "invalid report_len=%d. bytes: %02x %02x\n",
2690 report_len
, report_data
.report_head
[0],
2691 report_data
.report_head
[1]);
2695 /* Idle, no data for report. */
2696 if (report_len
== GEN5_RESP_LENGTH_SIZE
)
2699 ret
= cyapa_i2c_pip_read(cyapa
, (u8
*)&report_data
, report_len
);
2700 if (ret
!= report_len
) {
2701 dev_err(dev
, "failed to read %d bytes report data, (%d)\n",
2706 report_id
= report_data
.report_head
[GEN5_RESP_REPORT_ID_OFFSET
];
2707 if (report_id
== GEN5_WAKEUP_EVENT_REPORT_ID
&&
2708 report_len
== GEN5_WAKEUP_EVENT_SIZE
) {
2710 * Device wake event from deep sleep mode for touch.
2711 * This interrupt event is used to wake system up.
2714 } else if (report_id
!= GEN5_TOUCH_REPORT_ID
&&
2715 report_id
!= GEN5_BTN_REPORT_ID
&&
2716 report_id
!= GEN5_OLD_PUSH_BTN_REPORT_ID
&&
2717 report_id
!= GEN5_PUSH_BTN_REPORT_ID
) {
2718 /* Running in BL mode or unknown response data read. */
2719 dev_err(dev
, "invalid report_id=0x%02x\n", report_id
);
2723 if (report_id
== GEN5_TOUCH_REPORT_ID
&&
2724 (report_len
< GEN5_TOUCH_REPORT_HEAD_SIZE
||
2725 report_len
> GEN5_TOUCH_REPORT_MAX_SIZE
)) {
2726 /* Invalid report data length for finger packet. */
2727 dev_err(dev
, "invalid touch packet length=%d\n", report_len
);
2731 if ((report_id
== GEN5_BTN_REPORT_ID
||
2732 report_id
== GEN5_OLD_PUSH_BTN_REPORT_ID
||
2733 report_id
== GEN5_PUSH_BTN_REPORT_ID
) &&
2734 (report_len
< GEN5_BTN_REPORT_HEAD_SIZE
||
2735 report_len
> GEN5_BTN_REPORT_MAX_SIZE
)) {
2736 /* Invalid report data length of button packet. */
2737 dev_err(dev
, "invalid button packet length=%d\n", report_len
);
2741 if (report_id
== GEN5_TOUCH_REPORT_ID
)
2742 cyapa_gen5_report_touches(cyapa
, &report_data
);
2744 cyapa_gen5_report_buttons(cyapa
, &report_data
);
2749 static int cyapa_gen5_bl_activate(struct cyapa
*cyapa
) { return 0; }
2750 static int cyapa_gen5_bl_deactivate(struct cyapa
*cyapa
) { return 0; }
2752 const struct cyapa_dev_ops cyapa_gen5_ops
= {
2753 .check_fw
= cyapa_gen5_check_fw
,
2754 .bl_enter
= cyapa_gen5_bl_enter
,
2755 .bl_initiate
= cyapa_gen5_bl_initiate
,
2756 .update_fw
= cyapa_gen5_do_fw_update
,
2757 .bl_activate
= cyapa_gen5_bl_activate
,
2758 .bl_deactivate
= cyapa_gen5_bl_deactivate
,
2760 .show_baseline
= cyapa_gen5_show_baseline
,
2761 .calibrate_store
= cyapa_gen5_do_calibrate
,
2763 .initialize
= cyapa_gen5_initialize
,
2765 .state_parse
= cyapa_gen5_state_parse
,
2766 .operational_check
= cyapa_gen5_do_operational_check
,
2768 .irq_handler
= cyapa_gen5_irq_handler
,
2769 .irq_cmd_handler
= cyapa_gen5_irq_cmd_handler
,
2770 .sort_empty_output_data
= cyapa_empty_pip_output_data
,
2771 .set_power_mode
= cyapa_gen5_set_power_mode
,