blob: 5775d40b3d53994a754bd0f5a159adafbea65c3e [file] [log] [blame]
Dudley Du6972a852015-01-17 18:49:37 -08001/*
2 * Cypress APA trackpad with I2C interface
3 *
4 * Author: Dudley Du <dudl@cypress.com>
5 *
Dudley Du94897612015-07-20 16:49:06 -07006 * Copyright (C) 2014-2015 Cypress Semiconductor, Inc.
Dudley Du6972a852015-01-17 18:49:37 -08007 *
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>
Dudley Du17a28052015-03-02 09:37:59 -080020#include <asm/unaligned.h>
Dudley Du5812d302015-01-17 22:14:48 -080021#include <linux/crc-itu-t.h>
Dudley Du757cae52015-07-20 17:09:59 -070022#include <linux/pm_runtime.h>
Dudley Du6972a852015-01-17 18:49:37 -080023#include "cyapa.h"
24
25
Dudley Du94897612015-07-20 16:49:06 -070026/* Macro of TSG firmware image */
Dudley Du6972a852015-01-17 18:49:37 -080027#define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80
28#define CYAPA_TSG_IMG_FW_HDR_SIZE 13
29#define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
30#define CYAPA_TSG_IMG_START_ROW_NUM 0x002e
31#define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe
32#define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
33#define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \
34 CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
35#define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
36#define CYAPA_TSG_START_OF_APPLICATION 0x1700
37#define CYAPA_TSG_APP_INTEGRITY_SIZE 60
38#define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60
39#define CYAPA_TSG_BL_KEY_SIZE 8
40
41#define CYAPA_TSG_MAX_CMD_SIZE 256
42
Dudley Du94897612015-07-20 16:49:06 -070043/* Macro of PIP interface */
44#define PIP_BL_INITIATE_RESP_LEN 11
45#define PIP_BL_FAIL_EXIT_RESP_LEN 11
46#define PIP_BL_FAIL_EXIT_STATUS_CODE 0x0c
47#define PIP_BL_VERIFY_INTEGRITY_RESP_LEN 12
48#define PIP_BL_INTEGRITY_CHEKC_PASS 0x00
49#define PIP_BL_BLOCK_WRITE_RESP_LEN 11
Dudley Du6972a852015-01-17 18:49:37 -080050
Dudley Du94897612015-07-20 16:49:06 -070051#define PIP_TOUCH_REPORT_ID 0x01
52#define PIP_BTN_REPORT_ID 0x03
53#define PIP_WAKEUP_EVENT_REPORT_ID 0x04
54#define PIP_PUSH_BTN_REPORT_ID 0x06
55#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */
Dudley Du945525e2015-07-20 16:57:53 -070056#define PIP_PROXIMITY_REPORT_ID 0x07
57
58#define PIP_PROXIMITY_REPORT_SIZE 6
59#define PIP_PROXIMITY_DISTANCE_OFFSET 0x05
60#define PIP_PROXIMITY_DISTANCE_MASK 0x01
Dudley Du6972a852015-01-17 18:49:37 -080061
Dudley Du94897612015-07-20 16:49:06 -070062#define PIP_TOUCH_REPORT_HEAD_SIZE 7
63#define PIP_TOUCH_REPORT_MAX_SIZE 127
64#define PIP_BTN_REPORT_HEAD_SIZE 6
65#define PIP_BTN_REPORT_MAX_SIZE 14
66#define PIP_WAKEUP_EVENT_SIZE 4
Dudley Du6972a852015-01-17 18:49:37 -080067
Dudley Du94897612015-07-20 16:49:06 -070068#define PIP_NUMBER_OF_TOUCH_OFFSET 5
69#define PIP_NUMBER_OF_TOUCH_MASK 0x1f
70#define PIP_BUTTONS_OFFSET 5
71#define PIP_BUTTONS_MASK 0x0f
72#define PIP_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03)
73#define PIP_GET_TOUCH_ID(reg) ((reg) & 0x1f)
74#define PIP_TOUCH_TYPE_FINGER 0x00
75#define PIP_TOUCH_TYPE_PROXIMITY 0x01
76#define PIP_TOUCH_TYPE_HOVER 0x02
77#define PIP_GET_TOUCH_TYPE(reg) ((reg) & 0x07)
Dudley Du6972a852015-01-17 18:49:37 -080078
Dudley Du94897612015-07-20 16:49:06 -070079#define RECORD_EVENT_NONE 0
80#define RECORD_EVENT_TOUCHDOWN 1
81#define RECORD_EVENT_DISPLACE 2
82#define RECORD_EVENT_LIFTOFF 3
83
84#define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00
85#define PIP_SENSING_MODE_SELF_CAP 0x02
86
Dudley Du945525e2015-07-20 16:57:53 -070087#define PIP_SET_PROXIMITY 0x49
88
Dudley Du94897612015-07-20 16:49:06 -070089/* Macro of Gen5 */
90#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100
91#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe
92
93#define GEN5_POWER_STATE_ACTIVE 0x01
94#define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02
95#define GEN5_POWER_STATE_READY 0x03
96#define GEN5_POWER_STATE_IDLE 0x04
97#define GEN5_POWER_STATE_BTN_ONLY 0x05
98#define GEN5_POWER_STATE_OFF 0x06
99
100#define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */
101#define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */
Dudley Du6972a852015-01-17 18:49:37 -0800102
103#define GEN5_CMD_GET_PARAMETER 0x05
104#define GEN5_CMD_SET_PARAMETER 0x06
105#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d
106#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1
107#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f
108#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2
109#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c
110#define GEN5_PARAMETER_LP_INTRVL_SIZE 2
111
112#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08
113
Dudley Du6972a852015-01-17 18:49:37 -0800114#define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d
115#define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe
116#define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee
117#define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa
118#define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6
119
Dudley Du6972a852015-01-17 18:49:37 -0800120#define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00
121#define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01
122
123#define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
124
125#define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a
126#define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b
127#define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00
128#define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01
129#define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02
130#define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03
131#define GEN5_PANEL_SCAN_SELF_BASELINE 0x04
132#define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05
133
Dudley Du94897612015-07-20 16:49:06 -0700134/* The offset only valid for retrieve PWC and panel scan commands */
Dudley Du6972a852015-01-17 18:49:37 -0800135#define GEN5_RESP_DATA_STRUCTURE_OFFSET 10
136#define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07
137
Dudley Du6972a852015-01-17 18:49:37 -0800138
Dudley Du94897612015-07-20 16:49:06 -0700139struct cyapa_pip_touch_record {
Dudley Du6972a852015-01-17 18:49:37 -0800140 /*
141 * Bit 7 - 3: reserved
142 * Bit 2 - 0: touch type;
143 * 0 : standard finger;
Dudley Duc2c06c42015-07-20 16:53:30 -0700144 * 1 : proximity (Start supported in Gen5 TP).
145 * 2 : finger hover (defined, but not used yet.)
146 * 3 - 15 : reserved.
Dudley Du6972a852015-01-17 18:49:37 -0800147 */
148 u8 touch_type;
149
150 /*
151 * Bit 7: indicates touch liftoff status.
152 * 0 : touch is currently on the panel.
153 * 1 : touch record indicates a liftoff.
154 * Bit 6 - 5: indicates an event associated with this touch instance
155 * 0 : no event
156 * 1 : touchdown
157 * 2 : significant displacement (> active distance)
158 * 3 : liftoff (record reports last known coordinates)
159 * Bit 4 - 0: An arbitrary ID tag associated with a finger
160 * to allow tracking a touch as it moves around the panel.
161 */
162 u8 touch_tip_event_id;
163
164 /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
165 u8 x_lo;
166
167 /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
168 u8 x_hi;
169
170 /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
171 u8 y_lo;
172
173 /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
174 u8 y_hi;
175
Dudley Du94897612015-07-20 16:49:06 -0700176 /*
177 * The meaning of this value is different when touch_type is different.
178 * For standard finger type:
179 * Touch intensity in counts, pressure value.
Dudley Duc2c06c42015-07-20 16:53:30 -0700180 * For proximity type (Start supported in Gen5 TP):
181 * The distance, in surface units, between the contact and
182 * the surface.
Dudley Du94897612015-07-20 16:49:06 -0700183 **/
Dudley Du6972a852015-01-17 18:49:37 -0800184 u8 z;
185
186 /*
187 * The length of the major axis of the ellipse of contact between
188 * the finger and the panel (ABS_MT_TOUCH_MAJOR).
189 */
190 u8 major_axis_len;
191
192 /*
193 * The length of the minor axis of the ellipse of contact between
194 * the finger and the panel (ABS_MT_TOUCH_MINOR).
195 */
196 u8 minor_axis_len;
197
198 /*
199 * The length of the major axis of the approaching tool.
200 * (ABS_MT_WIDTH_MAJOR)
201 */
202 u8 major_tool_len;
203
204 /*
205 * The length of the minor axis of the approaching tool.
206 * (ABS_MT_WIDTH_MINOR)
207 */
208 u8 minor_tool_len;
209
210 /*
211 * The angle between the panel vertical axis and
212 * the major axis of the contact ellipse. This value is an 8-bit
213 * signed integer. The range is -127 to +127 (corresponding to
214 * -90 degree and +90 degree respectively).
215 * The positive direction is clockwise from the vertical axis.
216 * If the ellipse of contact degenerates into a circle,
217 * orientation is reported as 0.
218 */
219 u8 orientation;
220} __packed;
221
Dudley Du94897612015-07-20 16:49:06 -0700222struct cyapa_pip_report_data {
223 u8 report_head[PIP_TOUCH_REPORT_HEAD_SIZE];
224 struct cyapa_pip_touch_record touch_records[10];
Dudley Du6972a852015-01-17 18:49:37 -0800225} __packed;
226
Dudley Du5812d302015-01-17 22:14:48 -0800227struct cyapa_tsg_bin_image_head {
228 u8 head_size; /* Unit: bytes, including itself. */
229 u8 ttda_driver_major_version; /* Reserved as 0. */
230 u8 ttda_driver_minor_version; /* Reserved as 0. */
231 u8 fw_major_version;
232 u8 fw_minor_version;
233 u8 fw_revision_control_number[8];
Dudley Duc2c06c42015-07-20 16:53:30 -0700234 u8 silicon_id_hi;
235 u8 silicon_id_lo;
236 u8 chip_revision;
237 u8 family_id;
238 u8 bl_ver_maj;
239 u8 bl_ver_min;
Dudley Du5812d302015-01-17 22:14:48 -0800240} __packed;
241
242struct cyapa_tsg_bin_image_data_record {
243 u8 flash_array_id;
244 __be16 row_number;
245 /* The number of bytes of flash data contained in this record. */
246 __be16 record_len;
247 /* The flash program data. */
248 u8 record_data[CYAPA_TSG_FW_ROW_SIZE];
249} __packed;
250
251struct cyapa_tsg_bin_image {
252 struct cyapa_tsg_bin_image_head image_head;
253 struct cyapa_tsg_bin_image_data_record records[0];
254} __packed;
255
Dudley Du94897612015-07-20 16:49:06 -0700256struct pip_bl_packet_start {
Dudley Du5812d302015-01-17 22:14:48 -0800257 u8 sop; /* Start of packet, must be 01h */
258 u8 cmd_code;
259 __le16 data_length; /* Size of data parameter start from data[0] */
260} __packed;
261
Dudley Du94897612015-07-20 16:49:06 -0700262struct pip_bl_packet_end {
Dudley Du5812d302015-01-17 22:14:48 -0800263 __le16 crc;
264 u8 eop; /* End of packet, must be 17h */
265} __packed;
266
Dudley Du94897612015-07-20 16:49:06 -0700267struct pip_bl_cmd_head {
Dudley Du5812d302015-01-17 22:14:48 -0800268 __le16 addr; /* Output report register address, must be 0004h */
269 /* Size of packet not including output report register address */
270 __le16 length;
271 u8 report_id; /* Bootloader output report id, must be 40h */
272 u8 rsvd; /* Reserved, must be 0 */
Dudley Du94897612015-07-20 16:49:06 -0700273 struct pip_bl_packet_start packet_start;
Dudley Du5812d302015-01-17 22:14:48 -0800274 u8 data[0]; /* Command data variable based on commands */
275} __packed;
276
277/* Initiate bootload command data structure. */
Dudley Du94897612015-07-20 16:49:06 -0700278struct pip_bl_initiate_cmd_data {
Dudley Du5812d302015-01-17 22:14:48 -0800279 /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */
280 u8 key[CYAPA_TSG_BL_KEY_SIZE];
281 u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE];
282 __le16 metadata_crc;
283} __packed;
284
Dudley Du94897612015-07-20 16:49:06 -0700285struct tsg_bl_metadata_row_params {
Dudley Du5812d302015-01-17 22:14:48 -0800286 __le16 size;
Dmitry Torokhov2be72562015-01-19 15:59:31 -0800287 __le16 maximum_size;
Dudley Du5812d302015-01-17 22:14:48 -0800288 __le32 app_start;
289 __le16 app_len;
290 __le16 app_crc;
291 __le32 app_entry;
292 __le32 upgrade_start;
293 __le16 upgrade_len;
294 __le16 entry_row_crc;
295 u8 padding[36]; /* Padding data must be 0 */
296 __le16 metadata_crc; /* CRC starts at offset of 60 */
297} __packed;
298
299/* Bootload program and verify row command data structure */
Dudley Du94897612015-07-20 16:49:06 -0700300struct tsg_bl_flash_row_head {
Dudley Du5812d302015-01-17 22:14:48 -0800301 u8 flash_array_id;
302 __le16 flash_row_id;
303 u8 flash_data[0];
304} __packed;
305
Dudley Du94897612015-07-20 16:49:06 -0700306struct pip_app_cmd_head {
Dudley Du6972a852015-01-17 18:49:37 -0800307 __le16 addr; /* Output report register address, must be 0004h */
308 /* Size of packet not including output report register address */
309 __le16 length;
310 u8 report_id; /* Application output report id, must be 2Fh */
311 u8 rsvd; /* Reserved, must be 0 */
312 /*
313 * Bit 7: reserved, must be 0.
314 * Bit 6-0: command code.
315 */
316 u8 cmd_code;
317 u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
318} __packed;
319
Shailendra Verma7debcbb2015-05-26 13:44:06 -0700320/* Application get/set parameter command data structure */
Dudley Du6972a852015-01-17 18:49:37 -0800321struct gen5_app_set_parameter_data {
322 u8 parameter_id;
323 u8 parameter_size;
324 __le32 value;
325} __packed;
326
327struct gen5_app_get_parameter_data {
328 u8 parameter_id;
329} __packed;
330
Dudley Du6499d392015-01-17 22:16:01 -0800331struct gen5_retrieve_panel_scan_data {
332 __le16 read_offset;
333 __le16 read_elements;
334 u8 data_id;
335} __packed;
336
Dudley Du94897612015-07-20 16:49:06 -0700337u8 pip_read_sys_info[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 };
338u8 pip_bl_read_app_info[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
339 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
340 };
Dudley Du6972a852015-01-17 18:49:37 -0800341
Dudley Du94897612015-07-20 16:49:06 -0700342static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
Dudley Du5812d302015-01-17 22:14:48 -0800343 0xff, 0xfe, 0xfd, 0x5a };
344
Dudley Du3cd47862016-03-04 11:23:09 -0800345static int cyapa_pip_event_process(struct cyapa *cyapa,
346 struct cyapa_pip_report_data *report_data);
347
Dudley Du94897612015-07-20 16:49:06 -0700348int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa)
Dudley Du6972a852015-01-17 18:49:37 -0800349{
Dudley Du94897612015-07-20 16:49:06 -0700350 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800351
Dudley Du94897612015-07-20 16:49:06 -0700352 init_completion(&pip->cmd_ready);
353 atomic_set(&pip->cmd_issued, 0);
354 mutex_init(&pip->cmd_lock);
Dudley Du6972a852015-01-17 18:49:37 -0800355
Dudley Du3cd47862016-03-04 11:23:09 -0800356 mutex_init(&pip->pm_stage_lock);
357 pip->pm_stage = CYAPA_PM_DEACTIVE;
358
Dudley Du94897612015-07-20 16:49:06 -0700359 pip->resp_sort_func = NULL;
360 pip->in_progress_cmd = PIP_INVALID_CMD;
361 pip->resp_data = NULL;
362 pip->resp_len = NULL;
Dudley Du6972a852015-01-17 18:49:37 -0800363
364 cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
365 cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
366
367 return 0;
368}
369
370/* Return negative errno, or else the number of bytes read. */
Dudley Du94897612015-07-20 16:49:06 -0700371ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
Dudley Du6972a852015-01-17 18:49:37 -0800372{
373 int ret;
374
375 if (size == 0)
376 return 0;
377
378 if (!buf || size > CYAPA_REG_MAP_SIZE)
379 return -EINVAL;
380
381 ret = i2c_master_recv(cyapa->client, buf, size);
382
383 if (ret != size)
384 return (ret < 0) ? ret : -EIO;
Dudley Du6972a852015-01-17 18:49:37 -0800385 return size;
386}
387
388/**
389 * Return a negative errno code else zero on success.
390 */
Dudley Du94897612015-07-20 16:49:06 -0700391ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
Dudley Du6972a852015-01-17 18:49:37 -0800392{
393 int ret;
394
395 if (!buf || !size)
396 return -EINVAL;
397
398 ret = i2c_master_send(cyapa->client, buf, size);
399
400 if (ret != size)
401 return (ret < 0) ? ret : -EIO;
402
403 return 0;
404}
405
Dudley Du3cd47862016-03-04 11:23:09 -0800406static void cyapa_set_pip_pm_state(struct cyapa *cyapa,
407 enum cyapa_pm_stage pm_stage)
408{
409 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
410
411 mutex_lock(&pip->pm_stage_lock);
412 pip->pm_stage = pm_stage;
413 mutex_unlock(&pip->pm_stage_lock);
414}
415
416static void cyapa_reset_pip_pm_state(struct cyapa *cyapa)
417{
418 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
419
420 /* Indicates the pip->pm_stage is not valid. */
421 mutex_lock(&pip->pm_stage_lock);
422 pip->pm_stage = CYAPA_PM_DEACTIVE;
423 mutex_unlock(&pip->pm_stage_lock);
424}
425
426static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa)
427{
428 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
429 enum cyapa_pm_stage pm_stage;
430
431 mutex_lock(&pip->pm_stage_lock);
432 pm_stage = pip->pm_stage;
433 mutex_unlock(&pip->pm_stage_lock);
434
435 return pm_stage;
436}
437
Dudley Du6972a852015-01-17 18:49:37 -0800438/**
439 * This function is aimed to dump all not read data in Gen5 trackpad
440 * before send any command, otherwise, the interrupt line will be blocked.
441 */
Dudley Du94897612015-07-20 16:49:06 -0700442int cyapa_empty_pip_output_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -0800443 u8 *buf, int *len, cb_sort func)
444{
Dudley Du3cd47862016-03-04 11:23:09 -0800445 struct input_dev *input = cyapa->input;
Dudley Du94897612015-07-20 16:49:06 -0700446 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du3cd47862016-03-04 11:23:09 -0800447 enum cyapa_pm_stage pm_stage = cyapa_get_pip_pm_state(cyapa);
Dudley Du6972a852015-01-17 18:49:37 -0800448 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
Dudley Du94897612015-07-20 16:49:06 -0700479 error = cyapa_i2c_pip_read(cyapa, pip->empty_buf,
480 PIP_RESP_LENGTH_SIZE);
Dudley Du6972a852015-01-17 18:49:37 -0800481 if (error < 0)
482 return error;
483
Dudley Du94897612015-07-20 16:49:06 -0700484 length = get_unaligned_le16(pip->empty_buf);
485 if (length == PIP_RESP_LENGTH_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -0800486 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. */
Dudley Du94897612015-07-20 16:49:06 -0700493 length = PIP_RESP_LENGTH_SIZE;
Dudley Du6972a852015-01-17 18:49:37 -0800494 if (buf && buf_len && func &&
Dudley Du94897612015-07-20 16:49:06 -0700495 func(cyapa, pip->empty_buf, length)) {
Dudley Du6972a852015-01-17 18:49:37 -0800496 length = min(buf_len, length);
Dudley Du94897612015-07-20 16:49:06 -0700497 memcpy(buf, pip->empty_buf, length);
Dudley Du6972a852015-01-17 18:49:37 -0800498 *len = length;
499 /* Response found, success. */
500 return 0;
501 }
502 continue;
503 }
504
Dudley Du94897612015-07-20 16:49:06 -0700505 error = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length);
Dudley Du6972a852015-01-17 18:49:37 -0800506 if (error < 0)
507 return error;
508
509 report_count--;
510 empty_count = 0;
Dudley Du94897612015-07-20 16:49:06 -0700511 length = get_unaligned_le16(pip->empty_buf);
512 if (length <= PIP_RESP_LENGTH_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -0800513 empty_count++;
514 } else if (buf && buf_len && func &&
Dudley Du94897612015-07-20 16:49:06 -0700515 func(cyapa, pip->empty_buf, length)) {
Dudley Du6972a852015-01-17 18:49:37 -0800516 length = min(buf_len, length);
Dudley Du94897612015-07-20 16:49:06 -0700517 memcpy(buf, pip->empty_buf, length);
Dudley Du6972a852015-01-17 18:49:37 -0800518 *len = length;
519 /* Response found, success. */
520 return 0;
Dudley Du3cd47862016-03-04 11:23:09 -0800521 } else if (cyapa->operational && input && input->users &&
522 (pm_stage == CYAPA_PM_RUNTIME_RESUME ||
523 pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) {
524 /* Parse the data and report it if it's valid. */
525 cyapa_pip_event_process(cyapa,
526 (struct cyapa_pip_report_data *)pip->empty_buf);
Dudley Du6972a852015-01-17 18:49:37 -0800527 }
528
529 error = -EINVAL;
530 } while (report_count);
531
532 return error;
533}
534
535static int cyapa_do_i2c_pip_cmd_irq_sync(
536 struct cyapa *cyapa,
537 u8 *cmd, size_t cmd_len,
538 unsigned long timeout)
539{
Dudley Du94897612015-07-20 16:49:06 -0700540 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800541 int error;
542
543 /* Wait for interrupt to set ready completion */
Dudley Du94897612015-07-20 16:49:06 -0700544 init_completion(&pip->cmd_ready);
Dudley Du6972a852015-01-17 18:49:37 -0800545
Dudley Du94897612015-07-20 16:49:06 -0700546 atomic_inc(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800547 error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
548 if (error) {
Dudley Du94897612015-07-20 16:49:06 -0700549 atomic_dec(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800550 return (error < 0) ? error : -EIO;
551 }
552
553 /* Wait for interrupt to indicate command is completed. */
Dudley Du94897612015-07-20 16:49:06 -0700554 timeout = wait_for_completion_timeout(&pip->cmd_ready,
Dudley Du6972a852015-01-17 18:49:37 -0800555 msecs_to_jiffies(timeout));
556 if (timeout == 0) {
Dudley Du94897612015-07-20 16:49:06 -0700557 atomic_dec(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800558 return -ETIMEDOUT;
559 }
560
561 return 0;
562}
563
564static int cyapa_do_i2c_pip_cmd_polling(
565 struct cyapa *cyapa,
566 u8 *cmd, size_t cmd_len,
567 u8 *resp_data, int *resp_len,
568 unsigned long timeout,
569 cb_sort func)
570{
Dudley Du94897612015-07-20 16:49:06 -0700571 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800572 int tries;
573 int length;
574 int error;
575
Dudley Du94897612015-07-20 16:49:06 -0700576 atomic_inc(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800577 error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
578 if (error) {
Dudley Du94897612015-07-20 16:49:06 -0700579 atomic_dec(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800580 return error < 0 ? error : -EIO;
581 }
582
583 length = resp_len ? *resp_len : 0;
584 if (resp_data && resp_len && length != 0 && func) {
585 tries = timeout / 5;
586 do {
587 usleep_range(3000, 5000);
588 *resp_len = length;
589 error = cyapa_empty_pip_output_data(cyapa,
590 resp_data, resp_len, func);
591 if (error || *resp_len == 0)
592 continue;
593 else
594 break;
595 } while (--tries > 0);
596 if ((error || *resp_len == 0) || tries <= 0)
597 error = error ? error : -ETIMEDOUT;
598 }
599
Dudley Du94897612015-07-20 16:49:06 -0700600 atomic_dec(&pip->cmd_issued);
Dudley Du6972a852015-01-17 18:49:37 -0800601 return error;
602}
603
Dudley Du94897612015-07-20 16:49:06 -0700604int cyapa_i2c_pip_cmd_irq_sync(
Dudley Du6972a852015-01-17 18:49:37 -0800605 struct cyapa *cyapa,
606 u8 *cmd, int cmd_len,
607 u8 *resp_data, int *resp_len,
608 unsigned long timeout,
609 cb_sort func,
610 bool irq_mode)
611{
Dudley Du94897612015-07-20 16:49:06 -0700612 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800613 int error;
614
615 if (!cmd || !cmd_len)
616 return -EINVAL;
617
618 /* Commands must be serialized. */
Dudley Du94897612015-07-20 16:49:06 -0700619 error = mutex_lock_interruptible(&pip->cmd_lock);
Dudley Du6972a852015-01-17 18:49:37 -0800620 if (error)
621 return error;
622
Dudley Du94897612015-07-20 16:49:06 -0700623 pip->resp_sort_func = func;
624 pip->resp_data = resp_data;
625 pip->resp_len = resp_len;
Dudley Du6972a852015-01-17 18:49:37 -0800626
Dudley Du94897612015-07-20 16:49:06 -0700627 if (cmd_len >= PIP_MIN_APP_CMD_LENGTH &&
628 cmd[4] == PIP_APP_CMD_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -0800629 /* Application command */
Dudley Du94897612015-07-20 16:49:06 -0700630 pip->in_progress_cmd = cmd[6] & 0x7f;
631 } else if (cmd_len >= PIP_MIN_BL_CMD_LENGTH &&
632 cmd[4] == PIP_BL_CMD_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -0800633 /* Bootloader command */
Dudley Du94897612015-07-20 16:49:06 -0700634 pip->in_progress_cmd = cmd[7];
Dudley Du6972a852015-01-17 18:49:37 -0800635 }
636
637 /* Send command data, wait and read output response data's length. */
638 if (irq_mode) {
Dudley Du94897612015-07-20 16:49:06 -0700639 pip->is_irq_mode = true;
Dudley Du6972a852015-01-17 18:49:37 -0800640 error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
641 timeout);
642 if (error == -ETIMEDOUT && resp_data &&
643 resp_len && *resp_len != 0 && func) {
644 /*
645 * For some old version, there was no interrupt for
646 * the command response data, so need to poll here
647 * to try to get the response data.
648 */
649 error = cyapa_empty_pip_output_data(cyapa,
650 resp_data, resp_len, func);
651 if (error || *resp_len == 0)
652 error = error ? error : -ETIMEDOUT;
653 }
654 } else {
Dudley Du94897612015-07-20 16:49:06 -0700655 pip->is_irq_mode = false;
Dudley Du6972a852015-01-17 18:49:37 -0800656 error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
657 resp_data, resp_len, timeout, func);
658 }
659
Dudley Du94897612015-07-20 16:49:06 -0700660 pip->resp_sort_func = NULL;
661 pip->resp_data = NULL;
662 pip->resp_len = NULL;
663 pip->in_progress_cmd = PIP_INVALID_CMD;
Dudley Du6972a852015-01-17 18:49:37 -0800664
Dudley Du94897612015-07-20 16:49:06 -0700665 mutex_unlock(&pip->cmd_lock);
Dudley Du6972a852015-01-17 18:49:37 -0800666 return error;
667}
668
Dudley Du94897612015-07-20 16:49:06 -0700669bool cyapa_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -0800670 u8 *data, int len)
671{
Dudley Du94897612015-07-20 16:49:06 -0700672 if (!data || len < PIP_MIN_BL_RESP_LENGTH)
Dudley Du6972a852015-01-17 18:49:37 -0800673 return false;
674
675 /* Bootloader input report id 30h */
Dudley Du94897612015-07-20 16:49:06 -0700676 if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_BL_RESP_REPORT_ID &&
677 data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY &&
678 data[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY)
Dudley Du6972a852015-01-17 18:49:37 -0800679 return true;
680
681 return false;
682}
683
Dudley Du94897612015-07-20 16:49:06 -0700684bool cyapa_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -0800685 u8 *data, int len)
686{
Dudley Du94897612015-07-20 16:49:06 -0700687 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800688 int resp_len;
689
Dudley Du94897612015-07-20 16:49:06 -0700690 if (!data || len < PIP_MIN_APP_RESP_LENGTH)
Dudley Du6972a852015-01-17 18:49:37 -0800691 return false;
692
Dudley Du94897612015-07-20 16:49:06 -0700693 if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_APP_RESP_REPORT_ID &&
694 data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY) {
695 resp_len = get_unaligned_le16(&data[PIP_RESP_LENGTH_OFFSET]);
696 if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) == 0x00 &&
697 resp_len == PIP_UNSUPPORTED_CMD_RESP_LENGTH &&
698 data[5] == pip->in_progress_cmd) {
Dudley Du6972a852015-01-17 18:49:37 -0800699 /* Unsupported command code */
700 return false;
Dudley Du94897612015-07-20 16:49:06 -0700701 } else if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) ==
702 pip->in_progress_cmd) {
Dudley Du6972a852015-01-17 18:49:37 -0800703 /* Correct command response received */
704 return true;
705 }
706 }
707
708 return false;
709}
710
Dudley Du94897612015-07-20 16:49:06 -0700711static bool cyapa_sort_pip_application_launch_data(struct cyapa *cyapa,
Dudley Du5812d302015-01-17 22:14:48 -0800712 u8 *buf, int len)
713{
Dudley Du94897612015-07-20 16:49:06 -0700714 if (buf == NULL || len < PIP_RESP_LENGTH_SIZE)
Dudley Du5812d302015-01-17 22:14:48 -0800715 return false;
716
717 /*
718 * After reset or power on, trackpad device always sets to 0x00 0x00
719 * to indicate a reset or power on event.
720 */
721 if (buf[0] == 0 && buf[1] == 0)
722 return true;
723
724 return false;
725}
726
Dudley Du94897612015-07-20 16:49:06 -0700727static bool cyapa_sort_gen5_hid_descriptor_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -0800728 u8 *buf, int len)
729{
730 int resp_len;
731 int max_output_len;
732
733 /* Check hid descriptor. */
Dudley Du94897612015-07-20 16:49:06 -0700734 if (len != PIP_HID_DESCRIPTOR_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -0800735 return false;
736
Dudley Du94897612015-07-20 16:49:06 -0700737 resp_len = get_unaligned_le16(&buf[PIP_RESP_LENGTH_OFFSET]);
Dudley Du6972a852015-01-17 18:49:37 -0800738 max_output_len = get_unaligned_le16(&buf[16]);
Dudley Du94897612015-07-20 16:49:06 -0700739 if (resp_len == PIP_HID_DESCRIPTOR_SIZE) {
740 if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID &&
Dudley Du6972a852015-01-17 18:49:37 -0800741 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
742 /* BL mode HID Descriptor */
743 return true;
Dudley Du94897612015-07-20 16:49:06 -0700744 } else if ((buf[PIP_RESP_REPORT_ID_OFFSET] ==
745 PIP_HID_APP_REPORT_ID) &&
Dudley Du6972a852015-01-17 18:49:37 -0800746 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
747 /* APP mode HID Descriptor */
748 return true;
749 }
750 }
751
752 return false;
753}
754
Dudley Du94897612015-07-20 16:49:06 -0700755static bool cyapa_sort_pip_deep_sleep_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -0800756 u8 *buf, int len)
757{
Dudley Du94897612015-07-20 16:49:06 -0700758 if (len == PIP_DEEP_SLEEP_RESP_LENGTH &&
759 buf[PIP_RESP_REPORT_ID_OFFSET] ==
760 PIP_APP_DEEP_SLEEP_REPORT_ID &&
761 (buf[4] & PIP_DEEP_SLEEP_OPCODE_MASK) ==
762 PIP_DEEP_SLEEP_OPCODE)
Dudley Du6972a852015-01-17 18:49:37 -0800763 return true;
764 return false;
765}
766
767static int gen5_idle_state_parse(struct cyapa *cyapa)
768{
Dudley Du94897612015-07-20 16:49:06 -0700769 u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
Dudley Du6972a852015-01-17 18:49:37 -0800770 int max_output_len;
771 int length;
772 u8 cmd[2];
773 int ret;
774 int error;
775
776 /*
777 * Dump all buffered data firstly for the situation
778 * when the trackpad is just power on the cyapa go here.
779 */
780 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
781
782 memset(resp_data, 0, sizeof(resp_data));
783 ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
784 if (ret != 3)
785 return ret < 0 ? ret : -EIO;
786
Dudley Du94897612015-07-20 16:49:06 -0700787 length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]);
788 if (length == PIP_RESP_LENGTH_SIZE) {
789 /* Normal state of Gen5 with no data to response */
Dudley Du6972a852015-01-17 18:49:37 -0800790 cyapa->gen = CYAPA_GEN5;
791
792 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
793
794 /* Read description from trackpad device */
795 cmd[0] = 0x01;
796 cmd[1] = 0x00;
Dudley Du94897612015-07-20 16:49:06 -0700797 length = PIP_HID_DESCRIPTOR_SIZE;
Dudley Du6972a852015-01-17 18:49:37 -0800798 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
Dudley Du94897612015-07-20 16:49:06 -0700799 cmd, PIP_RESP_LENGTH_SIZE,
Dudley Du6972a852015-01-17 18:49:37 -0800800 resp_data, &length,
801 300,
Dudley Du94897612015-07-20 16:49:06 -0700802 cyapa_sort_gen5_hid_descriptor_data,
Dudley Du6972a852015-01-17 18:49:37 -0800803 false);
804 if (error)
805 return error;
806
807 length = get_unaligned_le16(
Dudley Du94897612015-07-20 16:49:06 -0700808 &resp_data[PIP_RESP_LENGTH_OFFSET]);
Dudley Du6972a852015-01-17 18:49:37 -0800809 max_output_len = get_unaligned_le16(&resp_data[16]);
Dudley Du94897612015-07-20 16:49:06 -0700810 if ((length == PIP_HID_DESCRIPTOR_SIZE ||
811 length == PIP_RESP_LENGTH_SIZE) &&
812 (resp_data[PIP_RESP_REPORT_ID_OFFSET] ==
813 PIP_HID_BL_REPORT_ID) &&
Dudley Du6972a852015-01-17 18:49:37 -0800814 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
815 /* BL mode HID Description read */
816 cyapa->state = CYAPA_STATE_GEN5_BL;
Dudley Du94897612015-07-20 16:49:06 -0700817 } else if ((length == PIP_HID_DESCRIPTOR_SIZE ||
818 length == PIP_RESP_LENGTH_SIZE) &&
819 (resp_data[PIP_RESP_REPORT_ID_OFFSET] ==
820 PIP_HID_APP_REPORT_ID) &&
Dudley Du6972a852015-01-17 18:49:37 -0800821 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
822 /* APP mode HID Description read */
823 cyapa->state = CYAPA_STATE_GEN5_APP;
824 } else {
825 /* Should not happen!!! */
826 cyapa->state = CYAPA_STATE_NO_DEVICE;
827 }
828 }
829
830 return 0;
831}
832
833static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
834{
835 int length;
836 u8 resp_data[32];
837 int max_output_len;
838 int ret;
839
840 /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
Shailendra Verma7debcbb2015-05-26 13:44:06 -0700841 * 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
Dudley Du6972a852015-01-17 18:49:37 -0800842 *
843 * Must read HID Description content through out,
844 * otherwise Gen5 trackpad cannot response next command
845 * or report any touch or button data.
846 */
847 ret = cyapa_i2c_pip_read(cyapa, resp_data,
Dudley Du94897612015-07-20 16:49:06 -0700848 PIP_HID_DESCRIPTOR_SIZE);
849 if (ret != PIP_HID_DESCRIPTOR_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -0800850 return ret < 0 ? ret : -EIO;
Dudley Du94897612015-07-20 16:49:06 -0700851 length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]);
Dudley Du6972a852015-01-17 18:49:37 -0800852 max_output_len = get_unaligned_le16(&resp_data[16]);
Dudley Du94897612015-07-20 16:49:06 -0700853 if (length == PIP_RESP_LENGTH_SIZE) {
854 if (reg_data[PIP_RESP_REPORT_ID_OFFSET] ==
855 PIP_HID_BL_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -0800856 /*
857 * BL mode HID Description has been previously
858 * read out.
859 */
860 cyapa->gen = CYAPA_GEN5;
861 cyapa->state = CYAPA_STATE_GEN5_BL;
862 } else {
863 /*
864 * APP mode HID Description has been previously
865 * read out.
866 */
867 cyapa->gen = CYAPA_GEN5;
868 cyapa->state = CYAPA_STATE_GEN5_APP;
869 }
Dudley Du94897612015-07-20 16:49:06 -0700870 } else if (length == PIP_HID_DESCRIPTOR_SIZE &&
871 resp_data[2] == PIP_HID_BL_REPORT_ID &&
Dudley Du6972a852015-01-17 18:49:37 -0800872 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
873 /* BL mode HID Description read. */
874 cyapa->gen = CYAPA_GEN5;
875 cyapa->state = CYAPA_STATE_GEN5_BL;
Dudley Du94897612015-07-20 16:49:06 -0700876 } else if (length == PIP_HID_DESCRIPTOR_SIZE &&
877 (resp_data[PIP_RESP_REPORT_ID_OFFSET] ==
878 PIP_HID_APP_REPORT_ID) &&
Dudley Du6972a852015-01-17 18:49:37 -0800879 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
880 /* APP mode HID Description read. */
881 cyapa->gen = CYAPA_GEN5;
882 cyapa->state = CYAPA_STATE_GEN5_APP;
883 } else {
884 /* Should not happen!!! */
885 cyapa->state = CYAPA_STATE_NO_DEVICE;
886 }
887
888 return 0;
889}
890
891static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
892{
893 int length;
894
Dudley Du94897612015-07-20 16:49:06 -0700895 length = get_unaligned_le16(&reg_data[PIP_RESP_LENGTH_OFFSET]);
896 switch (reg_data[PIP_RESP_REPORT_ID_OFFSET]) {
897 case PIP_TOUCH_REPORT_ID:
898 if (length < PIP_TOUCH_REPORT_HEAD_SIZE ||
899 length > PIP_TOUCH_REPORT_MAX_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -0800900 return -EINVAL;
901 break;
Dudley Du94897612015-07-20 16:49:06 -0700902 case PIP_BTN_REPORT_ID:
Dudley Du6972a852015-01-17 18:49:37 -0800903 case GEN5_OLD_PUSH_BTN_REPORT_ID:
Dudley Du94897612015-07-20 16:49:06 -0700904 case PIP_PUSH_BTN_REPORT_ID:
905 if (length < PIP_BTN_REPORT_HEAD_SIZE ||
906 length > PIP_BTN_REPORT_MAX_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -0800907 return -EINVAL;
908 break;
Dudley Du94897612015-07-20 16:49:06 -0700909 case PIP_WAKEUP_EVENT_REPORT_ID:
910 if (length != PIP_WAKEUP_EVENT_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -0800911 return -EINVAL;
912 break;
913 default:
914 return -EINVAL;
915 }
916
917 cyapa->gen = CYAPA_GEN5;
918 cyapa->state = CYAPA_STATE_GEN5_APP;
919 return 0;
920}
921
922static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
923{
Dudley Du94897612015-07-20 16:49:06 -0700924 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -0800925 int length;
926 int ret;
927
928 /*
929 * Must read report data through out,
930 * otherwise Gen5 trackpad cannot response next command
931 * or report any touch or button data.
932 */
Dudley Du94897612015-07-20 16:49:06 -0700933 length = get_unaligned_le16(&reg_data[PIP_RESP_LENGTH_OFFSET]);
934 ret = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length);
Dudley Du6972a852015-01-17 18:49:37 -0800935 if (ret != length)
936 return ret < 0 ? ret : -EIO;
937
Dudley Du94897612015-07-20 16:49:06 -0700938 if (length == PIP_RESP_LENGTH_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -0800939 /* Previous command has read the data through out. */
Dudley Du94897612015-07-20 16:49:06 -0700940 if (reg_data[PIP_RESP_REPORT_ID_OFFSET] ==
941 PIP_BL_RESP_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -0800942 /* Gen5 BL command response data detected */
943 cyapa->gen = CYAPA_GEN5;
944 cyapa->state = CYAPA_STATE_GEN5_BL;
945 } else {
946 /* Gen5 APP command response data detected */
947 cyapa->gen = CYAPA_GEN5;
948 cyapa->state = CYAPA_STATE_GEN5_APP;
949 }
Dudley Du94897612015-07-20 16:49:06 -0700950 } else if ((pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] ==
951 PIP_BL_RESP_REPORT_ID) &&
952 (pip->empty_buf[PIP_RESP_RSVD_OFFSET] ==
953 PIP_RESP_RSVD_KEY) &&
954 (pip->empty_buf[PIP_RESP_BL_SOP_OFFSET] ==
955 PIP_SOP_KEY) &&
956 (pip->empty_buf[length - 1] ==
957 PIP_EOP_KEY)) {
Dudley Du6972a852015-01-17 18:49:37 -0800958 /* Gen5 BL command response data detected */
959 cyapa->gen = CYAPA_GEN5;
960 cyapa->state = CYAPA_STATE_GEN5_BL;
Dudley Du94897612015-07-20 16:49:06 -0700961 } else if (pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] ==
962 PIP_APP_RESP_REPORT_ID &&
963 pip->empty_buf[PIP_RESP_RSVD_OFFSET] ==
964 PIP_RESP_RSVD_KEY) {
Dudley Du6972a852015-01-17 18:49:37 -0800965 /* Gen5 APP command response data detected */
966 cyapa->gen = CYAPA_GEN5;
967 cyapa->state = CYAPA_STATE_GEN5_APP;
968 } else {
969 /* Should not happen!!! */
970 cyapa->state = CYAPA_STATE_NO_DEVICE;
971 }
972
973 return 0;
974}
975
976static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
977{
978 int length;
979
980 if (!reg_data || len < 3)
981 return -EINVAL;
982
983 cyapa->state = CYAPA_STATE_NO_DEVICE;
984
985 /* Parse based on Gen5 characteristic registers and bits */
Dudley Du94897612015-07-20 16:49:06 -0700986 length = get_unaligned_le16(&reg_data[PIP_RESP_LENGTH_OFFSET]);
987 if (length == 0 || length == PIP_RESP_LENGTH_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -0800988 gen5_idle_state_parse(cyapa);
Dudley Du94897612015-07-20 16:49:06 -0700989 } else if (length == PIP_HID_DESCRIPTOR_SIZE &&
990 (reg_data[2] == PIP_HID_BL_REPORT_ID ||
991 reg_data[2] == PIP_HID_APP_REPORT_ID)) {
Dudley Du6972a852015-01-17 18:49:37 -0800992 gen5_hid_description_header_parse(cyapa, reg_data);
993 } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
994 length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
995 reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
996 /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
997 cyapa->gen = CYAPA_GEN5;
998 cyapa->state = CYAPA_STATE_GEN5_APP;
999 } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
1000 reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
Dudley Du94897612015-07-20 16:49:06 -07001001 /* 0x1D 0x00 0xFE is Gen5 BL report descriptor header. */
Dudley Du6972a852015-01-17 18:49:37 -08001002 cyapa->gen = CYAPA_GEN5;
1003 cyapa->state = CYAPA_STATE_GEN5_BL;
Dudley Du94897612015-07-20 16:49:06 -07001004 } else if (reg_data[2] == PIP_TOUCH_REPORT_ID ||
1005 reg_data[2] == PIP_BTN_REPORT_ID ||
Dudley Du6972a852015-01-17 18:49:37 -08001006 reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
Dudley Du94897612015-07-20 16:49:06 -07001007 reg_data[2] == PIP_PUSH_BTN_REPORT_ID ||
1008 reg_data[2] == PIP_WAKEUP_EVENT_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -08001009 gen5_report_data_header_parse(cyapa, reg_data);
Dudley Du94897612015-07-20 16:49:06 -07001010 } else if (reg_data[2] == PIP_BL_RESP_REPORT_ID ||
1011 reg_data[2] == PIP_APP_RESP_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -08001012 gen5_cmd_resp_header_parse(cyapa, reg_data);
1013 }
1014
1015 if (cyapa->gen == CYAPA_GEN5) {
1016 /*
1017 * Must read the content (e.g.: report description and so on)
1018 * from trackpad device throughout. Otherwise,
1019 * Gen5 trackpad cannot response to next command or
1020 * report any touch or button data later.
1021 */
1022 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1023
1024 if (cyapa->state == CYAPA_STATE_GEN5_APP ||
1025 cyapa->state == CYAPA_STATE_GEN5_BL)
1026 return 0;
1027 }
1028
1029 return -EAGAIN;
1030}
1031
Dudley Du94897612015-07-20 16:49:06 -07001032static struct cyapa_tsg_bin_image_data_record *
1033cyapa_get_image_record_data_num(const struct firmware *fw,
1034 int *record_num)
Dudley Du5812d302015-01-17 22:14:48 -08001035{
Dudley Du94897612015-07-20 16:49:06 -07001036 int head_size;
1037
1038 head_size = fw->data[0] + 1;
1039 *record_num = (fw->size - head_size) /
1040 sizeof(struct cyapa_tsg_bin_image_data_record);
1041 return (struct cyapa_tsg_bin_image_data_record *)&fw->data[head_size];
1042}
1043
1044int cyapa_pip_bl_initiate(struct cyapa *cyapa, const struct firmware *fw)
1045{
1046 struct cyapa_tsg_bin_image_data_record *image_records;
1047 struct pip_bl_cmd_head *bl_cmd_head;
1048 struct pip_bl_packet_start *bl_packet_start;
1049 struct pip_bl_initiate_cmd_data *cmd_data;
1050 struct pip_bl_packet_end *bl_packet_end;
Dudley Du5812d302015-01-17 22:14:48 -08001051 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1052 int cmd_len;
1053 u16 cmd_data_len;
1054 u16 cmd_crc = 0;
1055 u16 meta_data_crc = 0;
1056 u8 resp_data[11];
1057 int resp_len;
1058 int records_num;
1059 u8 *data;
1060 int error;
1061
1062 /* Try to dump all buffered report data before any send command. */
1063 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1064
1065 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
Dudley Du94897612015-07-20 16:49:06 -07001066 bl_cmd_head = (struct pip_bl_cmd_head *)cmd;
Dudley Du5812d302015-01-17 22:14:48 -08001067 cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
Dudley Du94897612015-07-20 16:49:06 -07001068 cmd_len = sizeof(struct pip_bl_cmd_head) + cmd_data_len +
1069 sizeof(struct pip_bl_packet_end);
Dudley Du5812d302015-01-17 22:14:48 -08001070
Dudley Du94897612015-07-20 16:49:06 -07001071 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
Dudley Du5812d302015-01-17 22:14:48 -08001072 put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001073 bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID;
Dudley Du5812d302015-01-17 22:14:48 -08001074
1075 bl_packet_start = &bl_cmd_head->packet_start;
Dudley Du94897612015-07-20 16:49:06 -07001076 bl_packet_start->sop = PIP_SOP_KEY;
1077 bl_packet_start->cmd_code = PIP_BL_CMD_INITIATE_BL;
Dudley Du5812d302015-01-17 22:14:48 -08001078 /* 8 key bytes and 128 bytes block size */
1079 put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length);
1080
Dudley Du94897612015-07-20 16:49:06 -07001081 cmd_data = (struct pip_bl_initiate_cmd_data *)bl_cmd_head->data;
1082 memcpy(cmd_data->key, cyapa_pip_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE);
Dudley Du5812d302015-01-17 22:14:48 -08001083
Dudley Du94897612015-07-20 16:49:06 -07001084 image_records = cyapa_get_image_record_data_num(fw, &records_num);
1085
Dudley Du5812d302015-01-17 22:14:48 -08001086 /* APP_INTEGRITY row is always the last row block */
Dudley Du94897612015-07-20 16:49:06 -07001087 data = image_records[records_num - 1].record_data;
Dudley Du5812d302015-01-17 22:14:48 -08001088 memcpy(cmd_data->metadata_raw_parameter, data,
1089 CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1090
1091 meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter,
1092 CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1093 put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc);
1094
Dudley Du94897612015-07-20 16:49:06 -07001095 bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data +
Dudley Du5812d302015-01-17 22:14:48 -08001096 cmd_data_len);
1097 cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
Dudley Du94897612015-07-20 16:49:06 -07001098 sizeof(struct pip_bl_packet_start) + cmd_data_len);
Dudley Du5812d302015-01-17 22:14:48 -08001099 put_unaligned_le16(cmd_crc, &bl_packet_end->crc);
Dudley Du94897612015-07-20 16:49:06 -07001100 bl_packet_end->eop = PIP_EOP_KEY;
Dudley Du5812d302015-01-17 22:14:48 -08001101
1102 resp_len = sizeof(resp_data);
1103 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1104 cmd, cmd_len,
1105 resp_data, &resp_len, 12000,
Dudley Du94897612015-07-20 16:49:06 -07001106 cyapa_sort_tsg_pip_bl_resp_data, true);
1107 if (error || resp_len != PIP_BL_INITIATE_RESP_LEN ||
1108 resp_data[2] != PIP_BL_RESP_REPORT_ID ||
1109 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Du5812d302015-01-17 22:14:48 -08001110 return error ? error : -EAGAIN;
1111
1112 return 0;
1113}
1114
Dudley Du94897612015-07-20 16:49:06 -07001115static bool cyapa_sort_pip_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
Dudley Du6972a852015-01-17 18:49:37 -08001116{
Dudley Du94897612015-07-20 16:49:06 -07001117 if (buf == NULL || len < PIP_RESP_LENGTH_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -08001118 return false;
1119
1120 if (buf[0] == 0 && buf[1] == 0)
1121 return true;
1122
1123 /* Exit bootloader failed for some reason. */
Dudley Du94897612015-07-20 16:49:06 -07001124 if (len == PIP_BL_FAIL_EXIT_RESP_LEN &&
1125 buf[PIP_RESP_REPORT_ID_OFFSET] ==
1126 PIP_BL_RESP_REPORT_ID &&
1127 buf[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY &&
1128 buf[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY &&
1129 buf[10] == PIP_EOP_KEY)
Dudley Du6972a852015-01-17 18:49:37 -08001130 return true;
1131
1132 return false;
1133}
1134
Dudley Du94897612015-07-20 16:49:06 -07001135int cyapa_pip_bl_exit(struct cyapa *cyapa)
Dudley Du6972a852015-01-17 18:49:37 -08001136{
1137
1138 u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
1139 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
1140 0x20, 0xc7, 0x17
1141 };
1142 u8 resp_data[11];
1143 int resp_len;
1144 int error;
1145
1146 resp_len = sizeof(resp_data);
1147 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1148 bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
1149 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001150 5000, cyapa_sort_pip_bl_exit_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08001151 if (error)
1152 return error;
1153
Dudley Du94897612015-07-20 16:49:06 -07001154 if (resp_len == PIP_BL_FAIL_EXIT_RESP_LEN ||
1155 resp_data[PIP_RESP_REPORT_ID_OFFSET] ==
1156 PIP_BL_RESP_REPORT_ID)
Dudley Du6972a852015-01-17 18:49:37 -08001157 return -EAGAIN;
1158
1159 if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
1160 return 0;
1161
1162 return -ENODEV;
1163}
1164
Dudley Du94897612015-07-20 16:49:06 -07001165int cyapa_pip_bl_enter(struct cyapa *cyapa)
Dudley Du5812d302015-01-17 22:14:48 -08001166{
1167 u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
1168 u8 resp_data[2];
1169 int resp_len;
1170 int error;
1171
1172 error = cyapa_poll_state(cyapa, 500);
1173 if (error < 0)
1174 return error;
Dudley Du5812d302015-01-17 22:14:48 -08001175
Dudley Du94897612015-07-20 16:49:06 -07001176 /* Already in bootloader mode, Skipping exit. */
1177 if (cyapa_is_pip_bl_mode(cyapa))
Dudley Du5812d302015-01-17 22:14:48 -08001178 return 0;
Dudley Du94897612015-07-20 16:49:06 -07001179 else if (!cyapa_is_pip_app_mode(cyapa))
1180 return -EINVAL;
Dudley Du5812d302015-01-17 22:14:48 -08001181
1182 /* Try to dump all buffered report data before any send command. */
1183 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1184
1185 /*
1186 * Send bootloader enter command to trackpad device,
1187 * after enter bootloader, the response data is two bytes of 0x00 0x00.
1188 */
1189 resp_len = sizeof(resp_data);
1190 memset(resp_data, 0, resp_len);
1191 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1192 cmd, sizeof(cmd),
1193 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001194 5000, cyapa_sort_pip_application_launch_data,
Dudley Du5812d302015-01-17 22:14:48 -08001195 true);
1196 if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
1197 return error < 0 ? error : -EAGAIN;
1198
1199 cyapa->operational = false;
Dudley Du94897612015-07-20 16:49:06 -07001200 if (cyapa->gen == CYAPA_GEN5)
1201 cyapa->state = CYAPA_STATE_GEN5_BL;
Dudley Duc2c06c42015-07-20 16:53:30 -07001202 else if (cyapa->gen == CYAPA_GEN6)
1203 cyapa->state = CYAPA_STATE_GEN6_BL;
1204 return 0;
1205}
1206
1207static int cyapa_pip_fw_head_check(struct cyapa *cyapa,
1208 struct cyapa_tsg_bin_image_head *image_head)
1209{
1210 if (image_head->head_size != 0x0C && image_head->head_size != 0x12)
1211 return -EINVAL;
1212
1213 switch (cyapa->gen) {
1214 case CYAPA_GEN6:
1215 if (image_head->family_id != 0x9B ||
1216 image_head->silicon_id_hi != 0x0B)
1217 return -EINVAL;
1218 break;
1219 case CYAPA_GEN5:
1220 /* Gen5 without proximity support. */
1221 if (cyapa->platform_ver < 2) {
1222 if (image_head->head_size == 0x0C)
1223 break;
1224 return -EINVAL;
1225 }
1226
1227 if (image_head->family_id != 0x91 ||
1228 image_head->silicon_id_hi != 0x02)
1229 return -EINVAL;
1230 break;
1231 default:
1232 return -EINVAL;
1233 }
1234
Dudley Du5812d302015-01-17 22:14:48 -08001235 return 0;
1236}
1237
Dudley Du94897612015-07-20 16:49:06 -07001238int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw)
Dudley Du5812d302015-01-17 22:14:48 -08001239{
1240 struct device *dev = &cyapa->client->dev;
Dudley Du94897612015-07-20 16:49:06 -07001241 struct cyapa_tsg_bin_image_data_record *image_records;
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001242 const struct cyapa_tsg_bin_image_data_record *app_integrity;
Dudley Du94897612015-07-20 16:49:06 -07001243 const struct tsg_bl_metadata_row_params *metadata;
1244 int flash_records_count;
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001245 u32 fw_app_start, fw_upgrade_start;
1246 u16 fw_app_len, fw_upgrade_len;
1247 u16 app_crc;
1248 u16 app_integrity_crc;
Dudley Du5812d302015-01-17 22:14:48 -08001249 int i;
1250
Dudley Duc2c06c42015-07-20 16:53:30 -07001251 /* Verify the firmware image not miss-used for Gen5 and Gen6. */
1252 if (cyapa_pip_fw_head_check(cyapa,
1253 (struct cyapa_tsg_bin_image_head *)fw->data)) {
1254 dev_err(dev, "%s: firmware image not match TP device.\n",
1255 __func__);
1256 return -EINVAL;
1257 }
1258
Dudley Du94897612015-07-20 16:49:06 -07001259 image_records =
1260 cyapa_get_image_record_data_num(fw, &flash_records_count);
Dudley Du5812d302015-01-17 22:14:48 -08001261
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001262 /*
1263 * APP_INTEGRITY row is always the last row block,
1264 * and the row id must be 0x01ff.
1265 */
Dudley Du94897612015-07-20 16:49:06 -07001266 app_integrity = &image_records[flash_records_count - 1];
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001267
1268 if (app_integrity->flash_array_id != 0x00 ||
1269 get_unaligned_be16(&app_integrity->row_number) != 0x01ff) {
Dudley Du5812d302015-01-17 22:14:48 -08001270 dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
1271 return -EINVAL;
1272 }
Dudley Du5812d302015-01-17 22:14:48 -08001273
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001274 metadata = (const void *)app_integrity->record_data;
Dudley Du5812d302015-01-17 22:14:48 -08001275
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001276 /* Verify app_integrity crc */
1277 app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data,
1278 CYAPA_TSG_APP_INTEGRITY_SIZE);
1279 if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) {
1280 dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
Dudley Du5812d302015-01-17 22:14:48 -08001281 return -EINVAL;
1282 }
1283
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001284 fw_app_start = get_unaligned_le32(&metadata->app_start);
1285 fw_app_len = get_unaligned_le16(&metadata->app_len);
1286 fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start);
1287 fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len);
1288
1289 if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE ||
1290 fw_app_len % CYAPA_TSG_FW_ROW_SIZE ||
1291 fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE ||
1292 fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) {
1293 dev_err(dev, "%s: invalid image alignment.\n", __func__);
Dudley Du5812d302015-01-17 22:14:48 -08001294 return -EINVAL;
1295 }
1296
Dudley Du94897612015-07-20 16:49:06 -07001297 /* Verify application image CRC. */
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001298 app_crc = 0xffffU;
1299 for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) {
Dudley Du94897612015-07-20 16:49:06 -07001300 const u8 *data = image_records[i].record_data;
1301
Dudley Du5812d302015-01-17 22:14:48 -08001302 app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
1303 }
1304
Dmitry Torokhov2be72562015-01-19 15:59:31 -08001305 if (app_crc != get_unaligned_le16(&metadata->app_crc)) {
Dudley Du5812d302015-01-17 22:14:48 -08001306 dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
1307 return -EINVAL;
1308 }
1309
1310 return 0;
1311}
1312
Dudley Du94897612015-07-20 16:49:06 -07001313static int cyapa_pip_write_fw_block(struct cyapa *cyapa,
Dudley Du5812d302015-01-17 22:14:48 -08001314 struct cyapa_tsg_bin_image_data_record *flash_record)
1315{
Dudley Du94897612015-07-20 16:49:06 -07001316 struct pip_bl_cmd_head *bl_cmd_head;
1317 struct pip_bl_packet_start *bl_packet_start;
1318 struct tsg_bl_flash_row_head *flash_row_head;
1319 struct pip_bl_packet_end *bl_packet_end;
Dudley Du5812d302015-01-17 22:14:48 -08001320 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1321 u16 cmd_len;
1322 u8 flash_array_id;
1323 u16 flash_row_id;
1324 u16 record_len;
1325 u8 *record_data;
1326 u16 data_len;
1327 u16 crc;
1328 u8 resp_data[11];
1329 int resp_len;
1330 int error;
1331
1332 flash_array_id = flash_record->flash_array_id;
1333 flash_row_id = get_unaligned_be16(&flash_record->row_number);
1334 record_len = get_unaligned_be16(&flash_record->record_len);
1335 record_data = flash_record->record_data;
1336
1337 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
Dudley Du94897612015-07-20 16:49:06 -07001338 bl_cmd_head = (struct pip_bl_cmd_head *)cmd;
Dudley Du5812d302015-01-17 22:14:48 -08001339 bl_packet_start = &bl_cmd_head->packet_start;
Dudley Du94897612015-07-20 16:49:06 -07001340 cmd_len = sizeof(struct pip_bl_cmd_head) +
1341 sizeof(struct tsg_bl_flash_row_head) +
Dudley Du5812d302015-01-17 22:14:48 -08001342 CYAPA_TSG_FLASH_MAP_BLOCK_SIZE +
Dudley Du94897612015-07-20 16:49:06 -07001343 sizeof(struct pip_bl_packet_end);
Dudley Du5812d302015-01-17 22:14:48 -08001344
Dudley Du94897612015-07-20 16:49:06 -07001345 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
Dudley Du5812d302015-01-17 22:14:48 -08001346 /* Don't include 2 bytes register address */
1347 put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001348 bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID;
1349 bl_packet_start->sop = PIP_SOP_KEY;
1350 bl_packet_start->cmd_code = PIP_BL_CMD_PROGRAM_VERIFY_ROW;
Dudley Du5812d302015-01-17 22:14:48 -08001351
1352 /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
Dudley Du94897612015-07-20 16:49:06 -07001353 data_len = sizeof(struct tsg_bl_flash_row_head) + record_len;
Dudley Du5812d302015-01-17 22:14:48 -08001354 put_unaligned_le16(data_len, &bl_packet_start->data_length);
1355
Dudley Du94897612015-07-20 16:49:06 -07001356 flash_row_head = (struct tsg_bl_flash_row_head *)bl_cmd_head->data;
Dudley Du5812d302015-01-17 22:14:48 -08001357 flash_row_head->flash_array_id = flash_array_id;
1358 put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id);
1359 memcpy(flash_row_head->flash_data, record_data, record_len);
1360
Dudley Du94897612015-07-20 16:49:06 -07001361 bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data +
Dudley Du5812d302015-01-17 22:14:48 -08001362 data_len);
1363 crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
Dudley Du94897612015-07-20 16:49:06 -07001364 sizeof(struct pip_bl_packet_start) + data_len);
Dudley Du5812d302015-01-17 22:14:48 -08001365 put_unaligned_le16(crc, &bl_packet_end->crc);
Dudley Du94897612015-07-20 16:49:06 -07001366 bl_packet_end->eop = PIP_EOP_KEY;
Dudley Du5812d302015-01-17 22:14:48 -08001367
1368 resp_len = sizeof(resp_data);
1369 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1370 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001371 500, cyapa_sort_tsg_pip_bl_resp_data, true);
1372 if (error || resp_len != PIP_BL_BLOCK_WRITE_RESP_LEN ||
1373 resp_data[2] != PIP_BL_RESP_REPORT_ID ||
1374 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Du5812d302015-01-17 22:14:48 -08001375 return error < 0 ? error : -EAGAIN;
1376
1377 return 0;
1378}
1379
Dudley Du94897612015-07-20 16:49:06 -07001380int cyapa_pip_do_fw_update(struct cyapa *cyapa,
Dudley Du5812d302015-01-17 22:14:48 -08001381 const struct firmware *fw)
1382{
1383 struct device *dev = &cyapa->client->dev;
Dudley Du94897612015-07-20 16:49:06 -07001384 struct cyapa_tsg_bin_image_data_record *image_records;
Dudley Du5812d302015-01-17 22:14:48 -08001385 int flash_records_count;
1386 int i;
1387 int error;
1388
1389 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1390
Dudley Du94897612015-07-20 16:49:06 -07001391 image_records =
1392 cyapa_get_image_record_data_num(fw, &flash_records_count);
1393
Dudley Du5812d302015-01-17 22:14:48 -08001394 /*
1395 * The last flash row 0x01ff has been written through bl_initiate
1396 * command, so DO NOT write flash 0x01ff to trackpad device.
1397 */
1398 for (i = 0; i < (flash_records_count - 1); i++) {
Dudley Du94897612015-07-20 16:49:06 -07001399 error = cyapa_pip_write_fw_block(cyapa, &image_records[i]);
Dudley Du5812d302015-01-17 22:14:48 -08001400 if (error) {
1401 dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
1402 __func__, error);
1403 return error;
1404 }
1405 }
1406
1407 return 0;
1408}
1409
Dudley Du6972a852015-01-17 18:49:37 -08001410static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
1411{
1412 u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
1413 u8 resp_data[6];
1414 int resp_len;
1415 int error;
1416
1417 cmd[7] = power_state;
1418 resp_len = sizeof(resp_data);
1419 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1420 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001421 500, cyapa_sort_tsg_pip_app_resp_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08001422 if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
Dudley Du94897612015-07-20 16:49:06 -07001423 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Du6972a852015-01-17 18:49:37 -08001424 return error < 0 ? error : -EINVAL;
1425
1426 return 0;
1427}
1428
1429static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
1430 u8 parameter_id, u16 interval_time)
1431{
Dudley Du94897612015-07-20 16:49:06 -07001432 struct pip_app_cmd_head *app_cmd_head;
Dudley Du6972a852015-01-17 18:49:37 -08001433 struct gen5_app_set_parameter_data *parameter_data;
1434 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1435 int cmd_len;
1436 u8 resp_data[7];
1437 int resp_len;
1438 u8 parameter_size;
1439 int error;
1440
1441 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
Dudley Du94897612015-07-20 16:49:06 -07001442 app_cmd_head = (struct pip_app_cmd_head *)cmd;
Dudley Du6972a852015-01-17 18:49:37 -08001443 parameter_data = (struct gen5_app_set_parameter_data *)
1444 app_cmd_head->parameter_data;
Dudley Du94897612015-07-20 16:49:06 -07001445 cmd_len = sizeof(struct pip_app_cmd_head) +
Dudley Du6972a852015-01-17 18:49:37 -08001446 sizeof(struct gen5_app_set_parameter_data);
1447
1448 switch (parameter_id) {
1449 case GEN5_PARAMETER_ACT_INTERVL_ID:
1450 parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1451 break;
1452 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1453 parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1454 break;
1455 case GEN5_PARAMETER_LP_INTRVL_ID:
1456 parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1457 break;
1458 default:
1459 return -EINVAL;
1460 }
1461
Dudley Du94897612015-07-20 16:49:06 -07001462 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Du6972a852015-01-17 18:49:37 -08001463 /*
1464 * Don't include unused parameter value bytes and
1465 * 2 bytes register address.
1466 */
1467 put_unaligned_le16(cmd_len - (4 - parameter_size) - 2,
1468 &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001469 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6972a852015-01-17 18:49:37 -08001470 app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1471 parameter_data->parameter_id = parameter_id;
1472 parameter_data->parameter_size = parameter_size;
1473 put_unaligned_le32((u32)interval_time, &parameter_data->value);
1474 resp_len = sizeof(resp_data);
1475 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1476 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001477 500, cyapa_sort_tsg_pip_app_resp_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08001478 if (error || resp_data[5] != parameter_id ||
1479 resp_data[6] != parameter_size ||
1480 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER))
1481 return error < 0 ? error : -EINVAL;
1482
1483 return 0;
1484}
1485
1486static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
1487 u8 parameter_id, u16 *interval_time)
1488{
Dudley Du94897612015-07-20 16:49:06 -07001489 struct pip_app_cmd_head *app_cmd_head;
Dudley Du6972a852015-01-17 18:49:37 -08001490 struct gen5_app_get_parameter_data *parameter_data;
1491 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1492 int cmd_len;
1493 u8 resp_data[11];
1494 int resp_len;
1495 u8 parameter_size;
1496 u16 mask, i;
1497 int error;
1498
1499 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
Dudley Du94897612015-07-20 16:49:06 -07001500 app_cmd_head = (struct pip_app_cmd_head *)cmd;
Dudley Du6972a852015-01-17 18:49:37 -08001501 parameter_data = (struct gen5_app_get_parameter_data *)
1502 app_cmd_head->parameter_data;
Dudley Du94897612015-07-20 16:49:06 -07001503 cmd_len = sizeof(struct pip_app_cmd_head) +
Dudley Du6972a852015-01-17 18:49:37 -08001504 sizeof(struct gen5_app_get_parameter_data);
1505
1506 *interval_time = 0;
1507 switch (parameter_id) {
1508 case GEN5_PARAMETER_ACT_INTERVL_ID:
1509 parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1510 break;
1511 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1512 parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1513 break;
1514 case GEN5_PARAMETER_LP_INTRVL_ID:
1515 parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1516 break;
1517 default:
1518 return -EINVAL;
1519 }
1520
Dudley Du94897612015-07-20 16:49:06 -07001521 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Du6972a852015-01-17 18:49:37 -08001522 /* Don't include 2 bytes register address */
1523 put_unaligned_le16(cmd_len - 2, &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001524 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6972a852015-01-17 18:49:37 -08001525 app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER;
1526 parameter_data->parameter_id = parameter_id;
1527
1528 resp_len = sizeof(resp_data);
1529 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1530 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001531 500, cyapa_sort_tsg_pip_app_resp_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08001532 if (error || resp_data[5] != parameter_id || resp_data[6] == 0 ||
1533 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER))
1534 return error < 0 ? error : -EINVAL;
1535
1536 mask = 0;
1537 for (i = 0; i < parameter_size; i++)
1538 mask |= (0xff << (i * 8));
1539 *interval_time = get_unaligned_le16(&resp_data[7]) & mask;
1540
1541 return 0;
1542}
1543
1544static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
1545{
Dudley Du94897612015-07-20 16:49:06 -07001546 struct pip_app_cmd_head *app_cmd_head;
Dudley Du6972a852015-01-17 18:49:37 -08001547 u8 cmd[10];
1548 u8 resp_data[7];
1549 int resp_len;
1550 int error;
1551
1552 memset(cmd, 0, sizeof(cmd));
Dudley Du94897612015-07-20 16:49:06 -07001553 app_cmd_head = (struct pip_app_cmd_head *)cmd;
Dudley Du6972a852015-01-17 18:49:37 -08001554
Dudley Du94897612015-07-20 16:49:06 -07001555 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Du6972a852015-01-17 18:49:37 -08001556 put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001557 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6972a852015-01-17 18:49:37 -08001558 app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1559 app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
1560 app_cmd_head->parameter_data[1] = 0x01;
1561 app_cmd_head->parameter_data[2] = 0x01;
1562 resp_len = sizeof(resp_data);
1563 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1564 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001565 500, cyapa_sort_tsg_pip_app_resp_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08001566 if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
1567 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) ||
1568 resp_data[6] != 0x01)
1569 return error < 0 ? error : -EINVAL;
1570
1571 return 0;
1572}
1573
Dudley Du945525e2015-07-20 16:57:53 -07001574int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable)
1575{
1576 u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, PIP_SET_PROXIMITY,
1577 (u8)!!enable
1578 };
1579 u8 resp_data[6];
1580 int resp_len;
1581 int error;
1582
1583 resp_len = sizeof(resp_data);
1584 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1585 resp_data, &resp_len,
1586 500, cyapa_sort_tsg_pip_app_resp_data, false);
1587 if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_SET_PROXIMITY) ||
1588 !PIP_CMD_COMPLETE_SUCCESS(resp_data)) {
1589 error = (error == -ETIMEDOUT) ? -EOPNOTSUPP : error;
1590 return error < 0 ? error : -EINVAL;
1591 }
1592
1593 return 0;
1594}
1595
Dudley Du94897612015-07-20 16:49:06 -07001596int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state)
Dudley Du6972a852015-01-17 18:49:37 -08001597{
1598 u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
1599 u8 resp_data[5];
1600 int resp_len;
1601 int error;
1602
Dudley Du94897612015-07-20 16:49:06 -07001603 cmd[2] = state & PIP_DEEP_SLEEP_STATE_MASK;
Dudley Du6972a852015-01-17 18:49:37 -08001604 resp_len = sizeof(resp_data);
1605 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1606 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001607 500, cyapa_sort_pip_deep_sleep_data, false);
1608 if (error || ((resp_data[3] & PIP_DEEP_SLEEP_STATE_MASK) != state))
Dudley Du6972a852015-01-17 18:49:37 -08001609 return -EINVAL;
1610
1611 return 0;
1612}
1613
1614static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
Dudley Du3cd47862016-03-04 11:23:09 -08001615 u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
Dudley Du6972a852015-01-17 18:49:37 -08001616{
1617 struct device *dev = &cyapa->client->dev;
1618 u8 power_state;
Dudley Du3cd47862016-03-04 11:23:09 -08001619 int error = 0;
Dudley Du6972a852015-01-17 18:49:37 -08001620
1621 if (cyapa->state != CYAPA_STATE_GEN5_APP)
1622 return 0;
1623
Dudley Du3cd47862016-03-04 11:23:09 -08001624 cyapa_set_pip_pm_state(cyapa, pm_stage);
1625
Dudley Du94897612015-07-20 16:49:06 -07001626 if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
Dudley Du6972a852015-01-17 18:49:37 -08001627 /*
1628 * Assume TP in deep sleep mode when driver is loaded,
1629 * avoid driver unload and reload command IO issue caused by TP
1630 * has been set into deep sleep mode when unloading.
1631 */
Dudley Du94897612015-07-20 16:49:06 -07001632 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
Dudley Du6972a852015-01-17 18:49:37 -08001633 }
1634
Dudley Du94897612015-07-20 16:49:06 -07001635 if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) &&
1636 PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
Dudley Du6972a852015-01-17 18:49:37 -08001637 if (cyapa_gen5_get_interval_time(cyapa,
1638 GEN5_PARAMETER_LP_INTRVL_ID,
1639 &cyapa->dev_sleep_time) != 0)
Dudley Du94897612015-07-20 16:49:06 -07001640 PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
Dudley Du6972a852015-01-17 18:49:37 -08001641
Dudley Du94897612015-07-20 16:49:06 -07001642 if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) {
Dudley Du6972a852015-01-17 18:49:37 -08001643 if (power_mode == PWR_MODE_OFF ||
1644 power_mode == PWR_MODE_FULL_ACTIVE ||
1645 power_mode == PWR_MODE_BTN_ONLY ||
Dudley Du94897612015-07-20 16:49:06 -07001646 PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
Dudley Du6972a852015-01-17 18:49:37 -08001647 /* Has in correct power mode state, early return. */
Dudley Du3cd47862016-03-04 11:23:09 -08001648 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001649 }
1650 }
1651
1652 if (power_mode == PWR_MODE_OFF) {
Dudley Du94897612015-07-20 16:49:06 -07001653 error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
Dudley Du6972a852015-01-17 18:49:37 -08001654 if (error) {
1655 dev_err(dev, "enter deep sleep fail: %d\n", error);
Dudley Du3cd47862016-03-04 11:23:09 -08001656 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001657 }
1658
Dudley Du94897612015-07-20 16:49:06 -07001659 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
Dudley Du3cd47862016-03-04 11:23:09 -08001660 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001661 }
1662
1663 /*
1664 * When trackpad in power off mode, it cannot change to other power
1665 * state directly, must be wake up from sleep firstly, then
1666 * continue to do next power sate change.
1667 */
Dudley Du94897612015-07-20 16:49:06 -07001668 if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
1669 error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
Dudley Du6972a852015-01-17 18:49:37 -08001670 if (error) {
1671 dev_err(dev, "deep sleep wake fail: %d\n", error);
Dudley Du3cd47862016-03-04 11:23:09 -08001672 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001673 }
1674 }
1675
1676 if (power_mode == PWR_MODE_FULL_ACTIVE) {
1677 error = cyapa_gen5_change_power_state(cyapa,
1678 GEN5_POWER_STATE_ACTIVE);
1679 if (error) {
1680 dev_err(dev, "change to active fail: %d\n", error);
Dudley Du3cd47862016-03-04 11:23:09 -08001681 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001682 }
1683
Dudley Du94897612015-07-20 16:49:06 -07001684 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
Dudley Du6972a852015-01-17 18:49:37 -08001685 } else if (power_mode == PWR_MODE_BTN_ONLY) {
1686 error = cyapa_gen5_change_power_state(cyapa,
1687 GEN5_POWER_STATE_BTN_ONLY);
1688 if (error) {
1689 dev_err(dev, "fail to button only mode: %d\n", error);
Dudley Du3cd47862016-03-04 11:23:09 -08001690 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001691 }
1692
Dudley Du94897612015-07-20 16:49:06 -07001693 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
Dudley Du6972a852015-01-17 18:49:37 -08001694 } else {
1695 /*
1696 * Continue to change power mode even failed to set
1697 * interval time, it won't affect the power mode change.
1698 * except the sleep interval time is not correct.
1699 */
Dudley Du94897612015-07-20 16:49:06 -07001700 if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) ||
1701 sleep_time != PIP_DEV_GET_SLEEP_TIME(cyapa))
Dudley Du6972a852015-01-17 18:49:37 -08001702 if (cyapa_gen5_set_interval_time(cyapa,
1703 GEN5_PARAMETER_LP_INTRVL_ID,
1704 sleep_time) == 0)
Dudley Du94897612015-07-20 16:49:06 -07001705 PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
Dudley Du6972a852015-01-17 18:49:37 -08001706
1707 if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
1708 power_state = GEN5_POWER_STATE_READY;
1709 else
1710 power_state = GEN5_POWER_STATE_IDLE;
1711 error = cyapa_gen5_change_power_state(cyapa, power_state);
1712 if (error) {
1713 dev_err(dev, "set power state to 0x%02x failed: %d\n",
1714 power_state, error);
Dudley Du3cd47862016-03-04 11:23:09 -08001715 goto out;
Dudley Du6972a852015-01-17 18:49:37 -08001716 }
1717
1718 /*
1719 * Disable pip report for a little time, firmware will
1720 * re-enable it automatically. It's used to fix the issue
1721 * that trackpad unable to report signal to wake system up
1722 * in the special situation that system is in suspending, and
1723 * at the same time, user touch trackpad to wake system up.
Shailendra Verma7debcbb2015-05-26 13:44:06 -07001724 * This function can avoid the data to be buffered when system
1725 * is suspending which may cause interrupt line unable to be
Dudley Du6972a852015-01-17 18:49:37 -08001726 * asserted again.
1727 */
Dudley Du3cd47862016-03-04 11:23:09 -08001728 if (pm_stage == CYAPA_PM_SUSPEND)
Dudley Du757cae52015-07-20 17:09:59 -07001729 cyapa_gen5_disable_pip_report(cyapa);
Dudley Du6972a852015-01-17 18:49:37 -08001730
Dudley Du94897612015-07-20 16:49:06 -07001731 PIP_DEV_SET_PWR_STATE(cyapa,
Dudley Du6972a852015-01-17 18:49:37 -08001732 cyapa_sleep_time_to_pwr_cmd(sleep_time));
1733 }
1734
Dudley Du3cd47862016-03-04 11:23:09 -08001735out:
1736 cyapa_reset_pip_pm_state(cyapa);
1737 return error;
Dudley Du6972a852015-01-17 18:49:37 -08001738}
1739
Dudley Du94897612015-07-20 16:49:06 -07001740int cyapa_pip_resume_scanning(struct cyapa *cyapa)
Dudley Du6499d392015-01-17 22:16:01 -08001741{
1742 u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
1743 u8 resp_data[6];
1744 int resp_len;
1745 int error;
1746
1747 /* Try to dump all buffered data before doing command. */
1748 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1749
1750 resp_len = sizeof(resp_data);
1751 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1752 cmd, sizeof(cmd),
1753 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001754 500, cyapa_sort_tsg_pip_app_resp_data, true);
Dudley Du6499d392015-01-17 22:16:01 -08001755 if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
1756 return -EINVAL;
1757
1758 /* Try to dump all buffered data when resuming scanning. */
1759 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1760
1761 return 0;
1762}
1763
Dudley Du94897612015-07-20 16:49:06 -07001764int cyapa_pip_suspend_scanning(struct cyapa *cyapa)
Dudley Du6499d392015-01-17 22:16:01 -08001765{
1766 u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
1767 u8 resp_data[6];
1768 int resp_len;
1769 int error;
1770
1771 /* Try to dump all buffered data before doing command. */
1772 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1773
1774 resp_len = sizeof(resp_data);
1775 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1776 cmd, sizeof(cmd),
1777 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001778 500, cyapa_sort_tsg_pip_app_resp_data, true);
Dudley Du6499d392015-01-17 22:16:01 -08001779 if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
1780 return -EINVAL;
1781
1782 /* Try to dump all buffered data when suspending scanning. */
1783 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1784
1785 return 0;
1786}
1787
Dudley Du94897612015-07-20 16:49:06 -07001788static int cyapa_pip_calibrate_pwcs(struct cyapa *cyapa,
Dudley Dudaceed12015-01-17 22:18:14 -08001789 u8 calibrate_sensing_mode_type)
1790{
Dudley Du94897612015-07-20 16:49:06 -07001791 struct pip_app_cmd_head *app_cmd_head;
Dudley Dudaceed12015-01-17 22:18:14 -08001792 u8 cmd[8];
1793 u8 resp_data[6];
1794 int resp_len;
1795 int error;
1796
1797 /* Try to dump all buffered data before doing command. */
1798 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1799
1800 memset(cmd, 0, sizeof(cmd));
Dudley Du94897612015-07-20 16:49:06 -07001801 app_cmd_head = (struct pip_app_cmd_head *)cmd;
1802 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Dudaceed12015-01-17 22:18:14 -08001803 put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07001804 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
1805 app_cmd_head->cmd_code = PIP_CMD_CALIBRATE;
Dudley Dudaceed12015-01-17 22:18:14 -08001806 app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type;
1807 resp_len = sizeof(resp_data);
1808 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1809 cmd, sizeof(cmd),
1810 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07001811 5000, cyapa_sort_tsg_pip_app_resp_data, true);
1812 if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_CMD_CALIBRATE) ||
1813 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Dudaceed12015-01-17 22:18:14 -08001814 return error < 0 ? error : -EAGAIN;
1815
1816 return 0;
1817}
1818
Dudley Du94897612015-07-20 16:49:06 -07001819ssize_t cyapa_pip_do_calibrate(struct device *dev,
Dudley Dudaceed12015-01-17 22:18:14 -08001820 struct device_attribute *attr,
1821 const char *buf, size_t count)
1822{
1823 struct cyapa *cyapa = dev_get_drvdata(dev);
1824 int error, calibrate_error;
1825
1826 /* 1. Suspend Scanning*/
Dudley Du94897612015-07-20 16:49:06 -07001827 error = cyapa_pip_suspend_scanning(cyapa);
Dudley Dudaceed12015-01-17 22:18:14 -08001828 if (error)
1829 return error;
1830
1831 /* 2. Do mutual capacitance fine calibrate. */
Dudley Du94897612015-07-20 16:49:06 -07001832 calibrate_error = cyapa_pip_calibrate_pwcs(cyapa,
1833 PIP_SENSING_MODE_MUTUAL_CAP_FINE);
Dudley Dudaceed12015-01-17 22:18:14 -08001834 if (calibrate_error)
1835 goto resume_scanning;
1836
1837 /* 3. Do self capacitance calibrate. */
Dudley Du94897612015-07-20 16:49:06 -07001838 calibrate_error = cyapa_pip_calibrate_pwcs(cyapa,
1839 PIP_SENSING_MODE_SELF_CAP);
Dudley Dudaceed12015-01-17 22:18:14 -08001840 if (calibrate_error)
1841 goto resume_scanning;
1842
1843resume_scanning:
1844 /* 4. Resume Scanning*/
Dudley Du94897612015-07-20 16:49:06 -07001845 error = cyapa_pip_resume_scanning(cyapa);
Dudley Dudaceed12015-01-17 22:18:14 -08001846 if (error || calibrate_error)
1847 return error ? error : calibrate_error;
1848
1849 return count;
1850}
1851
Dudley Du6499d392015-01-17 22:16:01 -08001852static s32 twos_complement_to_s32(s32 value, int num_bits)
1853{
1854 if (value >> (num_bits - 1))
1855 value |= -1 << num_bits;
1856 return value;
1857}
1858
1859static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
1860{
1861 int data_size;
1862 bool big_endian;
1863 bool unsigned_type;
1864 s32 value;
1865
1866 data_size = (data_format & 0x07);
1867 big_endian = ((data_format & 0x10) == 0x00);
1868 unsigned_type = ((data_format & 0x20) == 0x00);
1869
1870 if (buf_len < data_size)
1871 return 0;
1872
1873 switch (data_size) {
1874 case 1:
1875 value = buf[0];
1876 break;
1877 case 2:
1878 if (big_endian)
1879 value = get_unaligned_be16(buf);
1880 else
1881 value = get_unaligned_le16(buf);
1882 break;
1883 case 4:
1884 if (big_endian)
1885 value = get_unaligned_be32(buf);
1886 else
1887 value = get_unaligned_le32(buf);
1888 break;
1889 default:
1890 /* Should not happen, just as default case here. */
1891 value = 0;
1892 break;
1893 }
1894
1895 if (!unsigned_type)
1896 value = twos_complement_to_s32(value, data_size * 8);
1897
1898 return value;
1899}
1900
1901static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa,
1902 int *electrodes_rx, int *electrodes_tx)
1903{
1904 if (cyapa->electrodes_rx != 0) {
1905 *electrodes_rx = cyapa->electrodes_rx;
1906 *electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ?
1907 cyapa->electrodes_y : cyapa->electrodes_x;
1908 } else {
1909 *electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y);
1910 *electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y);
1911 }
1912}
1913
1914/*
1915 * Read all the global mutual or self idac data or mutual or self local PWC
1916 * data based on the @idac_data_type.
1917 * If the input value of @data_size is 0, then means read global mutual or
1918 * self idac data. For read global mutual idac data, @idac_max, @idac_min and
1919 * @idac_ave are in order used to return the max value of global mutual idac
1920 * data, the min value of global mutual idac and the average value of the
1921 * global mutual idac data. For read global self idac data, @idac_max is used
1922 * to return the global self cap idac data in Rx direction, @idac_min is used
1923 * to return the global self cap idac data in Tx direction. @idac_ave is not
1924 * used.
1925 * If the input value of @data_size is not 0, than means read the mutual or
1926 * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
1927 * return the max, min and average value of the mutual or self local PWC data.
Dudley Du94897612015-07-20 16:49:06 -07001928 * Note, in order to read mutual local PWC data, must read invoke this function
Dudley Du6499d392015-01-17 22:16:01 -08001929 * to read the mutual global idac data firstly to set the correct Rx number
1930 * value, otherwise, the read mutual idac and PWC data may not correct.
1931 */
1932static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
1933 u8 cmd_code, u8 idac_data_type, int *data_size,
1934 int *idac_max, int *idac_min, int *idac_ave)
1935{
Dudley Du94897612015-07-20 16:49:06 -07001936 struct pip_app_cmd_head *cmd_head;
Dudley Du6499d392015-01-17 22:16:01 -08001937 u8 cmd[12];
1938 u8 resp_data[256];
1939 int resp_len;
1940 int read_len;
1941 int value;
1942 u16 offset;
1943 int read_elements;
1944 bool read_global_idac;
1945 int sum, count, max_element_cnt;
1946 int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
1947 int electrodes_rx, electrodes_tx;
1948 int i;
1949 int error;
1950
Dudley Du94897612015-07-20 16:49:06 -07001951 if (cmd_code != PIP_RETRIEVE_DATA_STRUCTURE ||
Dudley Du6499d392015-01-17 22:16:01 -08001952 (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
1953 idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
1954 !data_size || !idac_max || !idac_min || !idac_ave)
1955 return -EINVAL;
1956
1957 *idac_max = INT_MIN;
1958 *idac_min = INT_MAX;
1959 sum = count = tmp_count = 0;
1960 electrodes_rx = electrodes_tx = 0;
1961 if (*data_size == 0) {
1962 /*
1963 * Read global idac values firstly.
1964 * Currently, no idac data exceed 4 bytes.
1965 */
1966 read_global_idac = true;
1967 offset = 0;
1968 *data_size = 4;
1969 tmp_max = INT_MIN;
1970 tmp_min = INT_MAX;
1971 tmp_ave = tmp_sum = tmp_count = 0;
1972
1973 if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1974 if (cyapa->aligned_electrodes_rx == 0) {
1975 cyapa_gen5_guess_electrodes(cyapa,
1976 &electrodes_rx, &electrodes_tx);
1977 cyapa->aligned_electrodes_rx =
1978 (electrodes_rx + 3) & ~3u;
1979 }
1980 max_element_cnt =
1981 (cyapa->aligned_electrodes_rx + 7) & ~7u;
1982 } else {
1983 max_element_cnt = 2;
1984 }
1985 } else {
1986 read_global_idac = false;
1987 if (*data_size > 4)
1988 *data_size = 4;
1989 /* Calculate the start offset in bytes of local PWC data. */
1990 if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1991 offset = cyapa->aligned_electrodes_rx * (*data_size);
1992 if (cyapa->electrodes_rx == cyapa->electrodes_x)
1993 electrodes_tx = cyapa->electrodes_y;
1994 else
1995 electrodes_tx = cyapa->electrodes_x;
1996 max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
1997 ~7u) * electrodes_tx;
Geert Uytterhoeven2523caa2015-03-02 09:39:24 -08001998 } else {
Dudley Du6499d392015-01-17 22:16:01 -08001999 offset = 2;
2000 max_element_cnt = cyapa->electrodes_x +
2001 cyapa->electrodes_y;
2002 max_element_cnt = (max_element_cnt + 3) & ~3u;
2003 }
2004 }
2005
2006 memset(cmd, 0, sizeof(cmd));
Dudley Du94897612015-07-20 16:49:06 -07002007 cmd_head = (struct pip_app_cmd_head *)cmd;
2008 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd_head->addr);
Dudley Du6499d392015-01-17 22:16:01 -08002009 put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07002010 cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6499d392015-01-17 22:16:01 -08002011 cmd_head->cmd_code = cmd_code;
2012 do {
2013 read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) /
2014 (*data_size);
2015 read_elements = min(read_elements, max_element_cnt - count);
2016 read_len = read_elements * (*data_size);
2017
2018 put_unaligned_le16(offset, &cmd_head->parameter_data[0]);
2019 put_unaligned_le16(read_len, &cmd_head->parameter_data[2]);
2020 cmd_head->parameter_data[4] = idac_data_type;
2021 resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
2022 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2023 cmd, sizeof(cmd),
2024 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07002025 500, cyapa_sort_tsg_pip_app_resp_data,
Dudley Du6499d392015-01-17 22:16:01 -08002026 true);
2027 if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
2028 !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
Dudley Du94897612015-07-20 16:49:06 -07002029 !PIP_CMD_COMPLETE_SUCCESS(resp_data) ||
Dudley Du6499d392015-01-17 22:16:01 -08002030 resp_data[6] != idac_data_type)
2031 return (error < 0) ? error : -EAGAIN;
2032 read_len = get_unaligned_le16(&resp_data[7]);
2033 if (read_len == 0)
2034 break;
2035
2036 *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
2037 if (read_len < *data_size)
2038 return -EINVAL;
2039
2040 if (read_global_idac &&
2041 idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
2042 /* Rx's self global idac data. */
2043 *idac_max = cyapa_parse_structure_data(
2044 resp_data[9],
2045 &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET],
2046 *data_size);
2047 /* Tx's self global idac data. */
2048 *idac_min = cyapa_parse_structure_data(
2049 resp_data[9],
2050 &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET +
2051 *data_size],
2052 *data_size);
2053 break;
2054 }
2055
2056 /* Read mutual global idac or local mutual/self PWC data. */
2057 offset += read_len;
2058 for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET);
2059 i += *data_size) {
2060 value = cyapa_parse_structure_data(resp_data[9],
2061 &resp_data[i], *data_size);
2062 *idac_min = min(value, *idac_min);
2063 *idac_max = max(value, *idac_max);
2064
2065 if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
2066 tmp_count < cyapa->aligned_electrodes_rx &&
2067 read_global_idac) {
2068 /*
Dudley Du94897612015-07-20 16:49:06 -07002069 * The value gap between global and local mutual
Dudley Du6499d392015-01-17 22:16:01 -08002070 * idac data must bigger than 50%.
2071 * Normally, global value bigger than 50,
2072 * local values less than 10.
2073 */
2074 if (!tmp_ave || value > tmp_ave / 2) {
2075 tmp_min = min(value, tmp_min);
2076 tmp_max = max(value, tmp_max);
2077 tmp_sum += value;
2078 tmp_count++;
2079
2080 tmp_ave = tmp_sum / tmp_count;
2081 }
2082 }
2083
2084 sum += value;
2085 count++;
2086
2087 if (count >= max_element_cnt)
2088 goto out;
2089 }
2090 } while (true);
2091
2092out:
2093 *idac_ave = count ? (sum / count) : 0;
2094
2095 if (read_global_idac &&
2096 idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
2097 if (tmp_count == 0)
2098 return 0;
2099
2100 if (tmp_count == cyapa->aligned_electrodes_rx) {
2101 cyapa->electrodes_rx = cyapa->electrodes_rx ?
2102 cyapa->electrodes_rx : electrodes_rx;
2103 } else if (tmp_count == electrodes_rx) {
2104 cyapa->electrodes_rx = cyapa->electrodes_rx ?
2105 cyapa->electrodes_rx : electrodes_rx;
2106 cyapa->aligned_electrodes_rx = electrodes_rx;
2107 } else {
2108 cyapa->electrodes_rx = cyapa->electrodes_rx ?
2109 cyapa->electrodes_rx : electrodes_tx;
2110 cyapa->aligned_electrodes_rx = tmp_count;
2111 }
2112
2113 *idac_min = tmp_min;
2114 *idac_max = tmp_max;
2115 *idac_ave = tmp_ave;
2116 }
2117
2118 return 0;
2119}
2120
2121static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
2122 int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
2123 int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
2124{
2125 int data_size;
2126 int error;
2127
2128 *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
2129 *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
2130
2131 data_size = 0;
2132 error = cyapa_gen5_read_idac_data(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002133 PIP_RETRIEVE_DATA_STRUCTURE,
Dudley Du6499d392015-01-17 22:16:01 -08002134 GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2135 &data_size,
2136 gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
2137 if (error)
2138 return error;
2139
2140 error = cyapa_gen5_read_idac_data(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002141 PIP_RETRIEVE_DATA_STRUCTURE,
Dudley Du6499d392015-01-17 22:16:01 -08002142 GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2143 &data_size,
2144 lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
2145 return error;
2146}
2147
2148static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
2149 int *gidac_self_rx, int *gidac_self_tx,
2150 int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
2151{
2152 int data_size;
2153 int error;
2154
2155 *gidac_self_rx = *gidac_self_tx = 0;
2156 *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
2157
2158 data_size = 0;
2159 error = cyapa_gen5_read_idac_data(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002160 PIP_RETRIEVE_DATA_STRUCTURE,
Dudley Du6499d392015-01-17 22:16:01 -08002161 GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2162 &data_size,
2163 lidac_self_max, lidac_self_min, lidac_self_ave);
2164 if (error)
2165 return error;
2166 *gidac_self_rx = *lidac_self_max;
2167 *gidac_self_tx = *lidac_self_min;
2168
2169 error = cyapa_gen5_read_idac_data(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002170 PIP_RETRIEVE_DATA_STRUCTURE,
Dudley Du6499d392015-01-17 22:16:01 -08002171 GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2172 &data_size,
2173 lidac_self_max, lidac_self_min, lidac_self_ave);
2174 return error;
2175}
2176
2177static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
2178{
Dudley Du94897612015-07-20 16:49:06 -07002179 struct pip_app_cmd_head *app_cmd_head;
Dudley Du6499d392015-01-17 22:16:01 -08002180 u8 cmd[7];
2181 u8 resp_data[6];
2182 int resp_len;
2183 int error;
2184
2185 memset(cmd, 0, sizeof(cmd));
Dudley Du94897612015-07-20 16:49:06 -07002186 app_cmd_head = (struct pip_app_cmd_head *)cmd;
2187 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Du6499d392015-01-17 22:16:01 -08002188 put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07002189 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6499d392015-01-17 22:16:01 -08002190 app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN;
2191 resp_len = sizeof(resp_data);
2192 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2193 cmd, sizeof(cmd),
2194 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07002195 500, cyapa_sort_tsg_pip_app_resp_data, true);
Dudley Du6499d392015-01-17 22:16:01 -08002196 if (error || resp_len != sizeof(resp_data) ||
2197 !VALID_CMD_RESP_HEADER(resp_data,
2198 GEN5_CMD_EXECUTE_PANEL_SCAN) ||
Dudley Du94897612015-07-20 16:49:06 -07002199 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Du6499d392015-01-17 22:16:01 -08002200 return error ? error : -EAGAIN;
2201
2202 return 0;
2203}
2204
2205static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
2206 u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
2207 int *raw_data_max, int *raw_data_min, int *raw_data_ave,
2208 u8 *buffer)
2209{
Dudley Du94897612015-07-20 16:49:06 -07002210 struct pip_app_cmd_head *app_cmd_head;
Dudley Du6499d392015-01-17 22:16:01 -08002211 struct gen5_retrieve_panel_scan_data *panel_sacn_data;
2212 u8 cmd[12];
2213 u8 resp_data[256]; /* Max bytes can transfer one time. */
2214 int resp_len;
2215 int read_elements;
2216 int read_len;
2217 u16 offset;
2218 s32 value;
2219 int sum, count;
2220 int data_size;
2221 s32 *intp;
2222 int i;
2223 int error;
2224
2225 if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
2226 (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
2227 !raw_data_max || !raw_data_min || !raw_data_ave)
2228 return -EINVAL;
2229
2230 intp = (s32 *)buffer;
2231 *raw_data_max = INT_MIN;
2232 *raw_data_min = INT_MAX;
2233 sum = count = 0;
2234 offset = 0;
2235 /* Assume max element size is 4 currently. */
2236 read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4;
2237 read_len = read_elements * 4;
Dudley Du94897612015-07-20 16:49:06 -07002238 app_cmd_head = (struct pip_app_cmd_head *)cmd;
2239 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
Dudley Du6499d392015-01-17 22:16:01 -08002240 put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
Dudley Du94897612015-07-20 16:49:06 -07002241 app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID;
Dudley Du6499d392015-01-17 22:16:01 -08002242 app_cmd_head->cmd_code = cmd_code;
2243 panel_sacn_data = (struct gen5_retrieve_panel_scan_data *)
2244 app_cmd_head->parameter_data;
2245 do {
2246 put_unaligned_le16(offset, &panel_sacn_data->read_offset);
2247 put_unaligned_le16(read_elements,
2248 &panel_sacn_data->read_elements);
2249 panel_sacn_data->data_id = raw_data_type;
2250
2251 resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
2252 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2253 cmd, sizeof(cmd),
2254 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07002255 500, cyapa_sort_tsg_pip_app_resp_data, true);
Dudley Du6499d392015-01-17 22:16:01 -08002256 if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
2257 !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
Dudley Du94897612015-07-20 16:49:06 -07002258 !PIP_CMD_COMPLETE_SUCCESS(resp_data) ||
Dudley Du6499d392015-01-17 22:16:01 -08002259 resp_data[6] != raw_data_type)
2260 return error ? error : -EAGAIN;
2261
2262 read_elements = get_unaligned_le16(&resp_data[7]);
2263 if (read_elements == 0)
2264 break;
2265
2266 data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
2267 offset += read_elements;
2268 if (read_elements) {
2269 for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET;
2270 i < (read_elements * data_size +
2271 GEN5_RESP_DATA_STRUCTURE_OFFSET);
2272 i += data_size) {
2273 value = cyapa_parse_structure_data(resp_data[9],
2274 &resp_data[i], data_size);
2275 *raw_data_min = min(value, *raw_data_min);
2276 *raw_data_max = max(value, *raw_data_max);
2277
2278 if (intp)
2279 put_unaligned_le32(value, &intp[count]);
2280
2281 sum += value;
2282 count++;
2283
2284 }
2285 }
2286
2287 if (count >= raw_data_max_num)
2288 break;
2289
2290 read_elements = (sizeof(resp_data) -
2291 GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size;
2292 read_len = read_elements * data_size;
2293 } while (true);
2294
2295 *raw_data_ave = count ? (sum / count) : 0;
2296
2297 return 0;
2298}
2299
2300static ssize_t cyapa_gen5_show_baseline(struct device *dev,
2301 struct device_attribute *attr, char *buf)
2302{
2303 struct cyapa *cyapa = dev_get_drvdata(dev);
2304 int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
2305 int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
2306 int gidac_self_rx, gidac_self_tx;
2307 int lidac_self_max, lidac_self_min, lidac_self_ave;
2308 int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
2309 int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
2310 int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
2311 int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
2312 int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
2313 int self_baseline_max, self_baseline_min, self_baseline_ave;
2314 int error, resume_error;
2315 int size;
2316
Dudley Du94897612015-07-20 16:49:06 -07002317 if (!cyapa_is_pip_app_mode(cyapa))
Dudley Du6499d392015-01-17 22:16:01 -08002318 return -EBUSY;
2319
2320 /* 1. Suspend Scanning*/
Dudley Du94897612015-07-20 16:49:06 -07002321 error = cyapa_pip_suspend_scanning(cyapa);
Dudley Du6499d392015-01-17 22:16:01 -08002322 if (error)
2323 return error;
2324
2325 /* 2. Read global and local mutual IDAC data. */
2326 gidac_self_rx = gidac_self_tx = 0;
2327 error = cyapa_gen5_read_mutual_idac_data(cyapa,
2328 &gidac_mutual_max, &gidac_mutual_min,
2329 &gidac_mutual_ave, &lidac_mutual_max,
2330 &lidac_mutual_min, &lidac_mutual_ave);
2331 if (error)
2332 goto resume_scanning;
2333
2334 /* 3. Read global and local self IDAC data. */
2335 error = cyapa_gen5_read_self_idac_data(cyapa,
2336 &gidac_self_rx, &gidac_self_tx,
2337 &lidac_self_max, &lidac_self_min,
2338 &lidac_self_ave);
2339 if (error)
2340 goto resume_scanning;
2341
Dudley Du94897612015-07-20 16:49:06 -07002342 /* 4. Execute panel scan. It must be executed before read data. */
Dudley Du6499d392015-01-17 22:16:01 -08002343 error = cyapa_gen5_execute_panel_scan(cyapa);
2344 if (error)
2345 goto resume_scanning;
2346
2347 /* 5. Retrieve panel scan, mutual cap raw data. */
2348 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2349 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2350 GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
2351 cyapa->electrodes_x * cyapa->electrodes_y,
2352 &raw_cap_mutual_max, &raw_cap_mutual_min,
2353 &raw_cap_mutual_ave,
2354 NULL);
2355 if (error)
2356 goto resume_scanning;
2357
2358 /* 6. Retrieve panel scan, self cap raw data. */
2359 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2360 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2361 GEN5_PANEL_SCAN_SELF_RAW_DATA,
2362 cyapa->electrodes_x + cyapa->electrodes_y,
2363 &raw_cap_self_max, &raw_cap_self_min,
2364 &raw_cap_self_ave,
2365 NULL);
2366 if (error)
2367 goto resume_scanning;
2368
2369 /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
2370 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2371 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2372 GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
2373 cyapa->electrodes_x * cyapa->electrodes_y,
2374 &mutual_diffdata_max, &mutual_diffdata_min,
2375 &mutual_diffdata_ave,
2376 NULL);
2377 if (error)
2378 goto resume_scanning;
2379
2380 /* 8. Retrieve panel scan, self cap diffcount raw data. */
2381 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2382 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2383 GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
2384 cyapa->electrodes_x + cyapa->electrodes_y,
2385 &self_diffdata_max, &self_diffdata_min,
2386 &self_diffdata_ave,
2387 NULL);
2388 if (error)
2389 goto resume_scanning;
2390
2391 /* 9. Retrieve panel scan, mutual cap baseline raw data. */
2392 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2393 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2394 GEN5_PANEL_SCAN_MUTUAL_BASELINE,
2395 cyapa->electrodes_x * cyapa->electrodes_y,
2396 &mutual_baseline_max, &mutual_baseline_min,
2397 &mutual_baseline_ave,
2398 NULL);
2399 if (error)
2400 goto resume_scanning;
2401
2402 /* 10. Retrieve panel scan, self cap baseline raw data. */
2403 error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2404 GEN5_CMD_RETRIEVE_PANEL_SCAN,
2405 GEN5_PANEL_SCAN_SELF_BASELINE,
2406 cyapa->electrodes_x + cyapa->electrodes_y,
2407 &self_baseline_max, &self_baseline_min,
2408 &self_baseline_ave,
2409 NULL);
2410 if (error)
2411 goto resume_scanning;
2412
2413resume_scanning:
2414 /* 11. Resume Scanning*/
Dudley Du94897612015-07-20 16:49:06 -07002415 resume_error = cyapa_pip_resume_scanning(cyapa);
Dudley Du6499d392015-01-17 22:16:01 -08002416 if (resume_error || error)
2417 return resume_error ? resume_error : error;
2418
2419 /* 12. Output data strings */
2420 size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
2421 gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
2422 lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
2423 gidac_self_rx, gidac_self_tx,
2424 lidac_self_min, lidac_self_max, lidac_self_ave);
2425 size += scnprintf(buf + size, PAGE_SIZE - size,
2426 "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
2427 raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
2428 raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
2429 mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
2430 self_diffdata_min, self_diffdata_max, self_diffdata_ave,
2431 mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
2432 self_baseline_min, self_baseline_max, self_baseline_ave);
2433 return size;
2434}
2435
Dudley Du94897612015-07-20 16:49:06 -07002436bool cyapa_pip_sort_system_info_data(struct cyapa *cyapa,
Dudley Du6972a852015-01-17 18:49:37 -08002437 u8 *buf, int len)
2438{
2439 /* Check the report id and command code */
2440 if (VALID_CMD_RESP_HEADER(buf, 0x02))
2441 return true;
2442
2443 return false;
2444}
2445
2446static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
2447{
Dudley Du94897612015-07-20 16:49:06 -07002448 u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH];
Dudley Du6972a852015-01-17 18:49:37 -08002449 int resp_len;
2450 int error;
2451
Dudley Du94897612015-07-20 16:49:06 -07002452 resp_len = sizeof(resp_data);
Dudley Du6972a852015-01-17 18:49:37 -08002453 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002454 pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH,
Dudley Du6972a852015-01-17 18:49:37 -08002455 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07002456 500, cyapa_sort_tsg_pip_bl_resp_data, false);
2457 if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH ||
2458 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
Dudley Du6972a852015-01-17 18:49:37 -08002459 return error ? error : -EIO;
2460
2461 memcpy(&cyapa->product_id[0], &resp_data[8], 5);
2462 cyapa->product_id[5] = '-';
2463 memcpy(&cyapa->product_id[6], &resp_data[13], 6);
2464 cyapa->product_id[12] = '-';
2465 memcpy(&cyapa->product_id[13], &resp_data[19], 2);
2466 cyapa->product_id[15] = '\0';
2467
2468 cyapa->fw_maj_ver = resp_data[22];
2469 cyapa->fw_min_ver = resp_data[23];
2470
Dudley Duc2c06c42015-07-20 16:53:30 -07002471 cyapa->platform_ver = (resp_data[26] >> PIP_BL_PLATFORM_VER_SHIFT) &
2472 PIP_BL_PLATFORM_VER_MASK;
2473
Dudley Du6972a852015-01-17 18:49:37 -08002474 return 0;
2475}
2476
2477static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
2478{
Dudley Du94897612015-07-20 16:49:06 -07002479 u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
Dudley Du6972a852015-01-17 18:49:37 -08002480 int resp_len;
2481 u16 product_family;
2482 int error;
2483
2484 resp_len = sizeof(resp_data);
2485 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002486 pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
Dudley Du6972a852015-01-17 18:49:37 -08002487 resp_data, &resp_len,
Dudley Du94897612015-07-20 16:49:06 -07002488 2000, cyapa_pip_sort_system_info_data, false);
Dudley Du6972a852015-01-17 18:49:37 -08002489 if (error || resp_len < sizeof(resp_data))
2490 return error ? error : -EIO;
2491
2492 product_family = get_unaligned_le16(&resp_data[7]);
Dudley Du94897612015-07-20 16:49:06 -07002493 if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
2494 PIP_PRODUCT_FAMILY_TRACKPAD)
Dudley Du6972a852015-01-17 18:49:37 -08002495 return -EINVAL;
2496
Dudley Duc2c06c42015-07-20 16:53:30 -07002497 cyapa->platform_ver = (resp_data[49] >> PIP_BL_PLATFORM_VER_SHIFT) &
2498 PIP_BL_PLATFORM_VER_MASK;
2499 if (cyapa->gen == CYAPA_GEN5 && cyapa->platform_ver < 2) {
2500 /* Gen5 firmware that does not support proximity. */
2501 cyapa->fw_maj_ver = resp_data[15];
2502 cyapa->fw_min_ver = resp_data[16];
2503 } else {
2504 cyapa->fw_maj_ver = resp_data[9];
2505 cyapa->fw_min_ver = resp_data[10];
2506 }
Dudley Du6972a852015-01-17 18:49:37 -08002507
2508 cyapa->electrodes_x = resp_data[52];
2509 cyapa->electrodes_y = resp_data[53];
2510
2511 cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100;
2512 cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
2513
2514 cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
2515 cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
2516
2517 cyapa->max_z = get_unaligned_le16(&resp_data[62]);
2518
2519 cyapa->x_origin = resp_data[64] & 0x01;
2520 cyapa->y_origin = resp_data[65] & 0x01;
2521
2522 cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
2523
2524 memcpy(&cyapa->product_id[0], &resp_data[33], 5);
2525 cyapa->product_id[5] = '-';
2526 memcpy(&cyapa->product_id[6], &resp_data[38], 6);
2527 cyapa->product_id[12] = '-';
2528 memcpy(&cyapa->product_id[13], &resp_data[44], 2);
2529 cyapa->product_id[15] = '\0';
2530
2531 if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
2532 !cyapa->physical_size_x || !cyapa->physical_size_y ||
2533 !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
2534 return -EINVAL;
2535
2536 return 0;
2537}
2538
2539static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
2540{
2541 struct device *dev = &cyapa->client->dev;
2542 int error;
2543
2544 if (cyapa->gen != CYAPA_GEN5)
2545 return -ENODEV;
2546
2547 switch (cyapa->state) {
2548 case CYAPA_STATE_GEN5_BL:
Dudley Du94897612015-07-20 16:49:06 -07002549 error = cyapa_pip_bl_exit(cyapa);
Dudley Du6972a852015-01-17 18:49:37 -08002550 if (error) {
Dudley Du94897612015-07-20 16:49:06 -07002551 /* Try to update trackpad product information. */
Dudley Du6972a852015-01-17 18:49:37 -08002552 cyapa_gen5_bl_query_data(cyapa);
2553 goto out;
2554 }
2555
2556 cyapa->state = CYAPA_STATE_GEN5_APP;
2557
2558 case CYAPA_STATE_GEN5_APP:
2559 /*
2560 * If trackpad device in deep sleep mode,
2561 * the app command will fail.
2562 * So always try to reset trackpad device to full active when
Dudley Du94897612015-07-20 16:49:06 -07002563 * the device state is required.
Dudley Du6972a852015-01-17 18:49:37 -08002564 */
2565 error = cyapa_gen5_set_power_mode(cyapa,
Dudley Du3cd47862016-03-04 11:23:09 -08002566 PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
Dudley Du6972a852015-01-17 18:49:37 -08002567 if (error)
2568 dev_warn(dev, "%s: failed to set power active mode.\n",
2569 __func__);
2570
Dudley Du945525e2015-07-20 16:57:53 -07002571 /* By default, the trackpad proximity function is enabled. */
Dudley Du0642ffd2015-07-30 11:26:39 -07002572 if (cyapa->platform_ver >= 2) {
2573 error = cyapa_pip_set_proximity(cyapa, true);
2574 if (error)
2575 dev_warn(dev,
2576 "%s: failed to enable proximity.\n",
2577 __func__);
2578 }
Dudley Du945525e2015-07-20 16:57:53 -07002579
Dudley Du6972a852015-01-17 18:49:37 -08002580 /* Get trackpad product information. */
2581 error = cyapa_gen5_get_query_data(cyapa);
2582 if (error)
2583 goto out;
2584 /* Only support product ID starting with CYTRA */
2585 if (memcmp(cyapa->product_id, product_id,
2586 strlen(product_id)) != 0) {
2587 dev_err(dev, "%s: unknown product ID (%s)\n",
2588 __func__, cyapa->product_id);
2589 error = -EINVAL;
2590 }
2591 break;
2592 default:
2593 error = -EINVAL;
2594 }
2595
2596out:
2597 return error;
2598}
2599
2600/*
2601 * Return false, do not continue process
2602 * Return true, continue process.
2603 */
Dudley Du94897612015-07-20 16:49:06 -07002604bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa)
Dudley Du6972a852015-01-17 18:49:37 -08002605{
Dudley Du94897612015-07-20 16:49:06 -07002606 struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
Dudley Du6972a852015-01-17 18:49:37 -08002607 int length;
2608
Dudley Du94897612015-07-20 16:49:06 -07002609 if (atomic_read(&pip->cmd_issued)) {
Dudley Du6972a852015-01-17 18:49:37 -08002610 /* Polling command response data. */
Dudley Du94897612015-07-20 16:49:06 -07002611 if (pip->is_irq_mode == false)
Dudley Du6972a852015-01-17 18:49:37 -08002612 return false;
2613
2614 /*
2615 * Read out all none command response data.
2616 * these output data may caused by user put finger on
2617 * trackpad when host waiting the command response.
2618 */
Dudley Du94897612015-07-20 16:49:06 -07002619 cyapa_i2c_pip_read(cyapa, pip->irq_cmd_buf,
2620 PIP_RESP_LENGTH_SIZE);
2621 length = get_unaligned_le16(pip->irq_cmd_buf);
2622 length = (length <= PIP_RESP_LENGTH_SIZE) ?
2623 PIP_RESP_LENGTH_SIZE : length;
2624 if (length > PIP_RESP_LENGTH_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -08002625 cyapa_i2c_pip_read(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002626 pip->irq_cmd_buf, length);
2627 if (!(pip->resp_sort_func &&
2628 pip->resp_sort_func(cyapa,
2629 pip->irq_cmd_buf, length))) {
Dudley Du6972a852015-01-17 18:49:37 -08002630 /*
Dudley Du94897612015-07-20 16:49:06 -07002631 * Cover the Gen5 V1 firmware issue.
2632 * The issue is no interrupt would be asserted from
2633 * trackpad device to host for the command response
2634 * ready event. Because when there was a finger touch
2635 * on trackpad device, and the firmware output queue
2636 * won't be empty (always with touch report data), so
2637 * the interrupt signal won't be asserted again until
2638 * the output queue was previous emptied.
2639 * This issue would happen in the scenario that
2640 * user always has his/her fingers touched on the
2641 * trackpad device during system booting/rebooting.
Dudley Du6972a852015-01-17 18:49:37 -08002642 */
Dudley Dua535a9f2015-01-22 08:17:16 -08002643 length = 0;
Dudley Du94897612015-07-20 16:49:06 -07002644 if (pip->resp_len)
2645 length = *pip->resp_len;
Dudley Du6972a852015-01-17 18:49:37 -08002646 cyapa_empty_pip_output_data(cyapa,
Dudley Du94897612015-07-20 16:49:06 -07002647 pip->resp_data,
Dudley Du6972a852015-01-17 18:49:37 -08002648 &length,
Dudley Du94897612015-07-20 16:49:06 -07002649 pip->resp_sort_func);
2650 if (pip->resp_len && length != 0) {
2651 *pip->resp_len = length;
2652 atomic_dec(&pip->cmd_issued);
2653 complete(&pip->cmd_ready);
Dudley Du6972a852015-01-17 18:49:37 -08002654 }
2655 return false;
2656 }
2657
Dudley Du94897612015-07-20 16:49:06 -07002658 if (pip->resp_data && pip->resp_len) {
2659 *pip->resp_len = (*pip->resp_len < length) ?
2660 *pip->resp_len : length;
2661 memcpy(pip->resp_data, pip->irq_cmd_buf,
2662 *pip->resp_len);
Dudley Du6972a852015-01-17 18:49:37 -08002663 }
Dudley Du94897612015-07-20 16:49:06 -07002664 atomic_dec(&pip->cmd_issued);
2665 complete(&pip->cmd_ready);
Dudley Du6972a852015-01-17 18:49:37 -08002666 return false;
2667 }
2668
2669 return true;
2670}
2671
Dudley Du94897612015-07-20 16:49:06 -07002672static void cyapa_pip_report_buttons(struct cyapa *cyapa,
2673 const struct cyapa_pip_report_data *report_data)
Dudley Du6972a852015-01-17 18:49:37 -08002674{
2675 struct input_dev *input = cyapa->input;
Dudley Du94897612015-07-20 16:49:06 -07002676 u8 buttons = report_data->report_head[PIP_BUTTONS_OFFSET];
Dudley Du6972a852015-01-17 18:49:37 -08002677
2678 buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
2679
2680 if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
2681 input_report_key(input, BTN_LEFT,
2682 !!(buttons & CAPABILITY_LEFT_BTN_MASK));
2683 }
2684 if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
2685 input_report_key(input, BTN_MIDDLE,
2686 !!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
2687 }
2688 if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
2689 input_report_key(input, BTN_RIGHT,
2690 !!(buttons & CAPABILITY_RIGHT_BTN_MASK));
2691 }
2692
2693 input_sync(input);
2694}
2695
Dudley Du945525e2015-07-20 16:57:53 -07002696static void cyapa_pip_report_proximity(struct cyapa *cyapa,
2697 const struct cyapa_pip_report_data *report_data)
2698{
2699 struct input_dev *input = cyapa->input;
2700 u8 distance = report_data->report_head[PIP_PROXIMITY_DISTANCE_OFFSET] &
2701 PIP_PROXIMITY_DISTANCE_MASK;
2702
2703 input_report_abs(input, ABS_DISTANCE, distance);
2704 input_sync(input);
2705}
2706
Dudley Du94897612015-07-20 16:49:06 -07002707static void cyapa_pip_report_slot_data(struct cyapa *cyapa,
2708 const struct cyapa_pip_touch_record *touch)
Dudley Du6972a852015-01-17 18:49:37 -08002709{
2710 struct input_dev *input = cyapa->input;
Dudley Du94897612015-07-20 16:49:06 -07002711 u8 event_id = PIP_GET_EVENT_ID(touch->touch_tip_event_id);
2712 int slot = PIP_GET_TOUCH_ID(touch->touch_tip_event_id);
Dudley Du6972a852015-01-17 18:49:37 -08002713 int x, y;
2714
2715 if (event_id == RECORD_EVENT_LIFTOFF)
2716 return;
2717
2718 input_mt_slot(input, slot);
2719 input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
2720 x = (touch->x_hi << 8) | touch->x_lo;
2721 if (cyapa->x_origin)
2722 x = cyapa->max_abs_x - x;
Dudley Du6972a852015-01-17 18:49:37 -08002723 y = (touch->y_hi << 8) | touch->y_lo;
2724 if (cyapa->y_origin)
2725 y = cyapa->max_abs_y - y;
Dudley Du94897612015-07-20 16:49:06 -07002726 input_report_abs(input, ABS_MT_POSITION_X, x);
Dudley Du6972a852015-01-17 18:49:37 -08002727 input_report_abs(input, ABS_MT_POSITION_Y, y);
Dudley Du945525e2015-07-20 16:57:53 -07002728 input_report_abs(input, ABS_DISTANCE, 0);
Dudley Du6972a852015-01-17 18:49:37 -08002729 input_report_abs(input, ABS_MT_PRESSURE,
2730 touch->z);
2731 input_report_abs(input, ABS_MT_TOUCH_MAJOR,
2732 touch->major_axis_len);
2733 input_report_abs(input, ABS_MT_TOUCH_MINOR,
2734 touch->minor_axis_len);
2735
2736 input_report_abs(input, ABS_MT_WIDTH_MAJOR,
2737 touch->major_tool_len);
2738 input_report_abs(input, ABS_MT_WIDTH_MINOR,
2739 touch->minor_tool_len);
2740
2741 input_report_abs(input, ABS_MT_ORIENTATION,
2742 touch->orientation);
2743}
2744
Dudley Du94897612015-07-20 16:49:06 -07002745static void cyapa_pip_report_touches(struct cyapa *cyapa,
2746 const struct cyapa_pip_report_data *report_data)
Dudley Du6972a852015-01-17 18:49:37 -08002747{
2748 struct input_dev *input = cyapa->input;
2749 unsigned int touch_num;
2750 int i;
2751
Dudley Du94897612015-07-20 16:49:06 -07002752 touch_num = report_data->report_head[PIP_NUMBER_OF_TOUCH_OFFSET] &
2753 PIP_NUMBER_OF_TOUCH_MASK;
Dudley Du6972a852015-01-17 18:49:37 -08002754
2755 for (i = 0; i < touch_num; i++)
Dudley Du94897612015-07-20 16:49:06 -07002756 cyapa_pip_report_slot_data(cyapa,
Dudley Du6972a852015-01-17 18:49:37 -08002757 &report_data->touch_records[i]);
2758
2759 input_mt_sync_frame(input);
2760 input_sync(input);
2761}
2762
Dudley Du94897612015-07-20 16:49:06 -07002763int cyapa_pip_irq_handler(struct cyapa *cyapa)
Dudley Du6972a852015-01-17 18:49:37 -08002764{
2765 struct device *dev = &cyapa->client->dev;
Dudley Du94897612015-07-20 16:49:06 -07002766 struct cyapa_pip_report_data report_data;
Dudley Du6972a852015-01-17 18:49:37 -08002767 unsigned int report_len;
Dudley Du94897612015-07-20 16:49:06 -07002768 int ret;
Dudley Du6972a852015-01-17 18:49:37 -08002769
Dudley Du94897612015-07-20 16:49:06 -07002770 if (!cyapa_is_pip_app_mode(cyapa)) {
Dudley Du6972a852015-01-17 18:49:37 -08002771 dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
2772 cyapa->gen, cyapa->state);
2773 return -EINVAL;
2774 }
2775
2776 ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
Dudley Du94897612015-07-20 16:49:06 -07002777 PIP_RESP_LENGTH_SIZE);
2778 if (ret != PIP_RESP_LENGTH_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -08002779 dev_err(dev, "failed to read length bytes, (%d)\n", ret);
2780 return -EINVAL;
2781 }
2782
2783 report_len = get_unaligned_le16(
Dudley Du94897612015-07-20 16:49:06 -07002784 &report_data.report_head[PIP_RESP_LENGTH_OFFSET]);
2785 if (report_len < PIP_RESP_LENGTH_SIZE) {
2786 /* Invalid length or internal reset happened. */
Dudley Du6972a852015-01-17 18:49:37 -08002787 dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
2788 report_len, report_data.report_head[0],
2789 report_data.report_head[1]);
2790 return -EINVAL;
2791 }
2792
2793 /* Idle, no data for report. */
Dudley Du94897612015-07-20 16:49:06 -07002794 if (report_len == PIP_RESP_LENGTH_SIZE)
Dudley Du6972a852015-01-17 18:49:37 -08002795 return 0;
2796
2797 ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
2798 if (ret != report_len) {
2799 dev_err(dev, "failed to read %d bytes report data, (%d)\n",
2800 report_len, ret);
2801 return -EINVAL;
2802 }
2803
Dudley Du3cd47862016-03-04 11:23:09 -08002804 return cyapa_pip_event_process(cyapa, &report_data);
2805}
2806
2807static int cyapa_pip_event_process(struct cyapa *cyapa,
2808 struct cyapa_pip_report_data *report_data)
2809{
2810 struct device *dev = &cyapa->client->dev;
2811 unsigned int report_len;
2812 u8 report_id;
2813
2814 report_len = get_unaligned_le16(
2815 &report_data->report_head[PIP_RESP_LENGTH_OFFSET]);
2816 /* Idle, no data for report. */
2817 if (report_len == PIP_RESP_LENGTH_SIZE)
2818 return 0;
2819
2820 report_id = report_data->report_head[PIP_RESP_REPORT_ID_OFFSET];
Dudley Du94897612015-07-20 16:49:06 -07002821 if (report_id == PIP_WAKEUP_EVENT_REPORT_ID &&
2822 report_len == PIP_WAKEUP_EVENT_SIZE) {
Dudley Du6972a852015-01-17 18:49:37 -08002823 /*
2824 * Device wake event from deep sleep mode for touch.
2825 * This interrupt event is used to wake system up.
Dudley Du757cae52015-07-20 17:09:59 -07002826 *
2827 * Note:
2828 * It will introduce about 20~40 ms additional delay
2829 * time in receiving for first valid touch report data.
2830 * The time is used to execute device runtime resume
2831 * process.
Dudley Du6972a852015-01-17 18:49:37 -08002832 */
Dudley Du757cae52015-07-20 17:09:59 -07002833 pm_runtime_get_sync(dev);
2834 pm_runtime_mark_last_busy(dev);
2835 pm_runtime_put_sync_autosuspend(dev);
Dudley Du6972a852015-01-17 18:49:37 -08002836 return 0;
Dudley Du94897612015-07-20 16:49:06 -07002837 } else if (report_id != PIP_TOUCH_REPORT_ID &&
2838 report_id != PIP_BTN_REPORT_ID &&
Dudley Du6972a852015-01-17 18:49:37 -08002839 report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
Dudley Du945525e2015-07-20 16:57:53 -07002840 report_id != PIP_PUSH_BTN_REPORT_ID &&
2841 report_id != PIP_PROXIMITY_REPORT_ID) {
Dudley Du6972a852015-01-17 18:49:37 -08002842 /* Running in BL mode or unknown response data read. */
2843 dev_err(dev, "invalid report_id=0x%02x\n", report_id);
2844 return -EINVAL;
2845 }
2846
Dudley Du94897612015-07-20 16:49:06 -07002847 if (report_id == PIP_TOUCH_REPORT_ID &&
2848 (report_len < PIP_TOUCH_REPORT_HEAD_SIZE ||
2849 report_len > PIP_TOUCH_REPORT_MAX_SIZE)) {
Dudley Du6972a852015-01-17 18:49:37 -08002850 /* Invalid report data length for finger packet. */
2851 dev_err(dev, "invalid touch packet length=%d\n", report_len);
2852 return 0;
2853 }
2854
Dudley Du94897612015-07-20 16:49:06 -07002855 if ((report_id == PIP_BTN_REPORT_ID ||
Dudley Du6972a852015-01-17 18:49:37 -08002856 report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
Dudley Du94897612015-07-20 16:49:06 -07002857 report_id == PIP_PUSH_BTN_REPORT_ID) &&
2858 (report_len < PIP_BTN_REPORT_HEAD_SIZE ||
2859 report_len > PIP_BTN_REPORT_MAX_SIZE)) {
Dudley Du6972a852015-01-17 18:49:37 -08002860 /* Invalid report data length of button packet. */
2861 dev_err(dev, "invalid button packet length=%d\n", report_len);
2862 return 0;
2863 }
2864
Dudley Du945525e2015-07-20 16:57:53 -07002865 if (report_id == PIP_PROXIMITY_REPORT_ID &&
2866 report_len != PIP_PROXIMITY_REPORT_SIZE) {
2867 /* Invalid report data length of proximity packet. */
2868 dev_err(dev, "invalid proximity data, length=%d\n", report_len);
2869 return 0;
2870 }
2871
Dudley Du94897612015-07-20 16:49:06 -07002872 if (report_id == PIP_TOUCH_REPORT_ID)
Dudley Du3cd47862016-03-04 11:23:09 -08002873 cyapa_pip_report_touches(cyapa, report_data);
Dudley Du945525e2015-07-20 16:57:53 -07002874 else if (report_id == PIP_PROXIMITY_REPORT_ID)
Dudley Du3cd47862016-03-04 11:23:09 -08002875 cyapa_pip_report_proximity(cyapa, report_data);
Dudley Du6972a852015-01-17 18:49:37 -08002876 else
Dudley Du3cd47862016-03-04 11:23:09 -08002877 cyapa_pip_report_buttons(cyapa, report_data);
Dudley Du6972a852015-01-17 18:49:37 -08002878
2879 return 0;
2880}
2881
Dudley Du94897612015-07-20 16:49:06 -07002882int cyapa_pip_bl_activate(struct cyapa *cyapa) { return 0; }
2883int cyapa_pip_bl_deactivate(struct cyapa *cyapa) { return 0; }
2884
Dudley Du5812d302015-01-17 22:14:48 -08002885
Dudley Du6972a852015-01-17 18:49:37 -08002886const struct cyapa_dev_ops cyapa_gen5_ops = {
Dudley Du94897612015-07-20 16:49:06 -07002887 .check_fw = cyapa_pip_check_fw,
2888 .bl_enter = cyapa_pip_bl_enter,
2889 .bl_initiate = cyapa_pip_bl_initiate,
2890 .update_fw = cyapa_pip_do_fw_update,
2891 .bl_activate = cyapa_pip_bl_activate,
2892 .bl_deactivate = cyapa_pip_bl_deactivate,
Dudley Du5812d302015-01-17 22:14:48 -08002893
Dudley Du6499d392015-01-17 22:16:01 -08002894 .show_baseline = cyapa_gen5_show_baseline,
Dudley Du94897612015-07-20 16:49:06 -07002895 .calibrate_store = cyapa_pip_do_calibrate,
Dudley Du6499d392015-01-17 22:16:01 -08002896
Dudley Du94897612015-07-20 16:49:06 -07002897 .initialize = cyapa_pip_cmd_state_initialize,
Dudley Du6972a852015-01-17 18:49:37 -08002898
2899 .state_parse = cyapa_gen5_state_parse,
2900 .operational_check = cyapa_gen5_do_operational_check,
2901
Dudley Du94897612015-07-20 16:49:06 -07002902 .irq_handler = cyapa_pip_irq_handler,
2903 .irq_cmd_handler = cyapa_pip_irq_cmd_handler,
Dudley Du6972a852015-01-17 18:49:37 -08002904 .sort_empty_output_data = cyapa_empty_pip_output_data,
2905 .set_power_mode = cyapa_gen5_set_power_mode,
Dudley Du945525e2015-07-20 16:57:53 -07002906
2907 .set_proximity = cyapa_pip_set_proximity,
Dudley Du6972a852015-01-17 18:49:37 -08002908};