2 * Cypress APA trackpad with I2C interface
4 * Author: Dudley Du <dudl@cypress.com>
6 * Copyright (C) 2015 Cypress Semiconductor, Inc.
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file COPYING in the main directory of this archive for
13 #include <linux/delay.h>
14 #include <linux/i2c.h>
15 #include <linux/input.h>
16 #include <linux/input/mt.h>
17 #include <linux/mutex.h>
18 #include <linux/completion.h>
19 #include <linux/slab.h>
20 #include <asm/unaligned.h>
21 #include <linux/crc-itu-t.h>
25 #define GEN6_ENABLE_CMD_IRQ 0x41
26 #define GEN6_DISABLE_CMD_IRQ 0x42
27 #define GEN6_ENABLE_DEV_IRQ 0x43
28 #define GEN6_DISABLE_DEV_IRQ 0x44
30 #define GEN6_POWER_MODE_ACTIVE 0x01
31 #define GEN6_POWER_MODE_LP_MODE1 0x02
32 #define GEN6_POWER_MODE_LP_MODE2 0x03
33 #define GEN6_POWER_MODE_BTN_ONLY 0x04
35 #define GEN6_SET_POWER_MODE_INTERVAL 0x47
36 #define GEN6_GET_POWER_MODE_INTERVAL 0x48
38 #define GEN6_MAX_RX_NUM 14
39 #define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00
40 #define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12
43 struct pip_app_cmd_head
{
47 u8 resv
; /* Reserved, must be 0 */
48 u8 cmd_code
; /* bit7: resv, set to 0; bit6~0: command code.*/
51 struct pip_app_resp_head
{
54 u8 resv
; /* Reserved, must be 0 */
55 u8 cmd_code
; /* bit7: TGL; bit6~0: command code.*/
57 * The value of data_status can be the first byte of data or
58 * the command status or the unsupported command code depending on the
59 * requested command code.
64 struct pip_fixed_info
{
70 static u8 pip_get_bl_info
[] = {
71 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
72 0x00, 0x00, 0x70, 0x9E, 0x17
75 static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa
*cyapa
,
78 if (len
!= PIP_HID_DESCRIPTOR_SIZE
)
81 if (buf
[PIP_RESP_REPORT_ID_OFFSET
] == PIP_HID_APP_REPORT_ID
||
82 buf
[PIP_RESP_REPORT_ID_OFFSET
] == PIP_HID_BL_REPORT_ID
)
88 static int cyapa_get_pip_fixed_info(struct cyapa
*cyapa
,
89 struct pip_fixed_info
*pip_info
, bool is_bootloader
)
91 u8 resp_data
[PIP_READ_SYS_INFO_RESP_LENGTH
];
97 /* Read Bootloader Information to determine Gen5 or Gen6. */
98 resp_len
= sizeof(resp_data
);
99 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
100 pip_get_bl_info
, sizeof(pip_get_bl_info
),
101 resp_data
, &resp_len
,
102 2000, cyapa_sort_tsg_pip_bl_resp_data
,
104 if (error
|| resp_len
< PIP_BL_GET_INFO_RESP_LENGTH
)
105 return error
? error
: -EIO
;
107 pip_info
->family_id
= resp_data
[8];
108 pip_info
->silicon_id_low
= resp_data
[10];
109 pip_info
->silicon_id_high
= resp_data
[11];
114 /* Get App System Information to determine Gen5 or Gen6. */
115 resp_len
= sizeof(resp_data
);
116 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
117 pip_read_sys_info
, PIP_READ_SYS_INFO_CMD_LENGTH
,
118 resp_data
, &resp_len
,
119 2000, cyapa_pip_sort_system_info_data
, false);
120 if (error
|| resp_len
< PIP_READ_SYS_INFO_RESP_LENGTH
)
121 return error
? error
: -EIO
;
123 product_family
= get_unaligned_le16(&resp_data
[7]);
124 if ((product_family
& PIP_PRODUCT_FAMILY_MASK
) !=
125 PIP_PRODUCT_FAMILY_TRACKPAD
)
128 pip_info
->family_id
= resp_data
[19];
129 pip_info
->silicon_id_low
= resp_data
[21];
130 pip_info
->silicon_id_high
= resp_data
[22];
136 int cyapa_pip_state_parse(struct cyapa
*cyapa
, u8
*reg_data
, int len
)
138 u8 cmd
[] = { 0x01, 0x00};
139 struct pip_fixed_info pip_info
;
140 u8 resp_data
[PIP_HID_DESCRIPTOR_SIZE
];
145 cyapa
->state
= CYAPA_STATE_NO_DEVICE
;
147 /* Try to wake from it deep sleep state if it is. */
148 cyapa_pip_deep_sleep(cyapa
, PIP_DEEP_SLEEP_STATE_ON
);
150 /* Empty the buffer queue to get fresh data with later commands. */
151 cyapa_empty_pip_output_data(cyapa
, NULL
, NULL
, NULL
);
154 * Read description info from trackpad device to determine running in
155 * APP mode or Bootloader mode.
157 resp_len
= PIP_HID_DESCRIPTOR_SIZE
;
158 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
160 resp_data
, &resp_len
,
162 cyapa_sort_pip_hid_descriptor_data
,
167 if (resp_data
[PIP_RESP_REPORT_ID_OFFSET
] == PIP_HID_BL_REPORT_ID
)
168 is_bootloader
= true;
169 else if (resp_data
[PIP_RESP_REPORT_ID_OFFSET
] == PIP_HID_APP_REPORT_ID
)
170 is_bootloader
= false;
174 /* Get PIP fixed information to determine Gen5 or Gen6. */
175 memset(&pip_info
, 0, sizeof(struct pip_fixed_info
));
176 error
= cyapa_get_pip_fixed_info(cyapa
, &pip_info
, is_bootloader
);
180 if (pip_info
.family_id
== 0x9B && pip_info
.silicon_id_high
== 0x0B) {
181 cyapa
->gen
= CYAPA_GEN6
;
182 cyapa
->state
= is_bootloader
? CYAPA_STATE_GEN6_BL
183 : CYAPA_STATE_GEN6_APP
;
184 } else if (pip_info
.family_id
== 0x91 &&
185 pip_info
.silicon_id_high
== 0x02) {
186 cyapa
->gen
= CYAPA_GEN5
;
187 cyapa
->state
= is_bootloader
? CYAPA_STATE_GEN5_BL
188 : CYAPA_STATE_GEN5_APP
;
194 static int cyapa_gen6_read_sys_info(struct cyapa
*cyapa
)
196 u8 resp_data
[PIP_READ_SYS_INFO_RESP_LENGTH
];
202 /* Get App System Information to determine Gen5 or Gen6. */
203 resp_len
= sizeof(resp_data
);
204 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
205 pip_read_sys_info
, PIP_READ_SYS_INFO_CMD_LENGTH
,
206 resp_data
, &resp_len
,
207 2000, cyapa_pip_sort_system_info_data
, false);
208 if (error
|| resp_len
< sizeof(resp_data
))
209 return error
? error
: -EIO
;
211 product_family
= get_unaligned_le16(&resp_data
[7]);
212 if ((product_family
& PIP_PRODUCT_FAMILY_MASK
) !=
213 PIP_PRODUCT_FAMILY_TRACKPAD
)
216 cyapa
->platform_ver
= (resp_data
[67] >> PIP_BL_PLATFORM_VER_SHIFT
) &
217 PIP_BL_PLATFORM_VER_MASK
;
218 cyapa
->fw_maj_ver
= resp_data
[9];
219 cyapa
->fw_min_ver
= resp_data
[10];
221 cyapa
->electrodes_x
= resp_data
[33];
222 cyapa
->electrodes_y
= resp_data
[34];
224 cyapa
->physical_size_x
= get_unaligned_le16(&resp_data
[35]) / 100;
225 cyapa
->physical_size_y
= get_unaligned_le16(&resp_data
[37]) / 100;
227 cyapa
->max_abs_x
= get_unaligned_le16(&resp_data
[39]);
228 cyapa
->max_abs_y
= get_unaligned_le16(&resp_data
[41]);
230 cyapa
->max_z
= get_unaligned_le16(&resp_data
[43]);
232 cyapa
->x_origin
= resp_data
[45] & 0x01;
233 cyapa
->y_origin
= resp_data
[46] & 0x01;
235 cyapa
->btn_capability
= (resp_data
[70] << 3) & CAPABILITY_BTN_MASK
;
237 memcpy(&cyapa
->product_id
[0], &resp_data
[51], 5);
238 cyapa
->product_id
[5] = '-';
239 memcpy(&cyapa
->product_id
[6], &resp_data
[56], 6);
240 cyapa
->product_id
[12] = '-';
241 memcpy(&cyapa
->product_id
[13], &resp_data
[62], 2);
242 cyapa
->product_id
[15] = '\0';
244 /* Get the number of Rx electrodes. */
245 rotat_align
= resp_data
[68];
246 cyapa
->electrodes_rx
=
247 rotat_align
? cyapa
->electrodes_y
: cyapa
->electrodes_x
;
248 cyapa
->aligned_electrodes_rx
= (cyapa
->electrodes_rx
+ 3) & ~3u;
250 if (!cyapa
->electrodes_x
|| !cyapa
->electrodes_y
||
251 !cyapa
->physical_size_x
|| !cyapa
->physical_size_y
||
252 !cyapa
->max_abs_x
|| !cyapa
->max_abs_y
|| !cyapa
->max_z
)
258 static int cyapa_gen6_bl_read_app_info(struct cyapa
*cyapa
)
260 u8 resp_data
[PIP_BL_APP_INFO_RESP_LENGTH
];
264 resp_len
= sizeof(resp_data
);
265 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
266 pip_bl_read_app_info
, PIP_BL_READ_APP_INFO_CMD_LENGTH
,
267 resp_data
, &resp_len
,
268 500, cyapa_sort_tsg_pip_bl_resp_data
, false);
269 if (error
|| resp_len
< PIP_BL_APP_INFO_RESP_LENGTH
||
270 !PIP_CMD_COMPLETE_SUCCESS(resp_data
))
271 return error
? error
: -EIO
;
273 cyapa
->fw_maj_ver
= resp_data
[8];
274 cyapa
->fw_min_ver
= resp_data
[9];
276 cyapa
->platform_ver
= (resp_data
[12] >> PIP_BL_PLATFORM_VER_SHIFT
) &
277 PIP_BL_PLATFORM_VER_MASK
;
279 memcpy(&cyapa
->product_id
[0], &resp_data
[13], 5);
280 cyapa
->product_id
[5] = '-';
281 memcpy(&cyapa
->product_id
[6], &resp_data
[18], 6);
282 cyapa
->product_id
[12] = '-';
283 memcpy(&cyapa
->product_id
[13], &resp_data
[24], 2);
284 cyapa
->product_id
[15] = '\0';
290 static int cyapa_gen6_config_dev_irq(struct cyapa
*cyapa
, u8 cmd_code
)
292 u8 cmd
[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code
};
297 resp_len
= sizeof(resp_data
);
298 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
, cmd
, sizeof(cmd
),
299 resp_data
, &resp_len
,
300 500, cyapa_sort_tsg_pip_app_resp_data
, false);
301 if (error
|| !VALID_CMD_RESP_HEADER(resp_data
, cmd_code
) ||
302 !PIP_CMD_COMPLETE_SUCCESS(resp_data
)
304 return error
< 0 ? error
: -EINVAL
;
309 static int cyapa_gen6_set_proximity(struct cyapa
*cyapa
, bool enable
)
313 cyapa_gen6_config_dev_irq(cyapa
, GEN6_DISABLE_CMD_IRQ
);
314 error
= cyapa_pip_set_proximity(cyapa
, enable
);
315 cyapa_gen6_config_dev_irq(cyapa
, GEN6_ENABLE_CMD_IRQ
);
320 static int cyapa_gen6_change_power_state(struct cyapa
*cyapa
, u8 power_mode
)
322 u8 cmd
[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode
};
327 resp_len
= sizeof(resp_data
);
328 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
, cmd
, sizeof(cmd
),
329 resp_data
, &resp_len
,
330 500, cyapa_sort_tsg_pip_app_resp_data
, false);
331 if (error
|| !VALID_CMD_RESP_HEADER(resp_data
, 0x46))
332 return error
< 0 ? error
: -EINVAL
;
334 /* New power state applied in device not match the set power state. */
335 if (resp_data
[5] != power_mode
)
341 static int cyapa_gen6_set_interval_setting(struct cyapa
*cyapa
,
342 struct gen6_interval_setting
*interval_setting
)
344 struct gen6_set_interval_cmd
{
348 u8 rsvd
; /* Reserved, must be 0 */
350 __le16 active_interval
;
353 } __packed set_interval_cmd
;
358 memset(&set_interval_cmd
, 0, sizeof(set_interval_cmd
));
359 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR
, &set_interval_cmd
.addr
);
360 put_unaligned_le16(sizeof(set_interval_cmd
) - 2,
361 &set_interval_cmd
.length
);
362 set_interval_cmd
.report_id
= PIP_APP_CMD_REPORT_ID
;
363 set_interval_cmd
.cmd_code
= GEN6_SET_POWER_MODE_INTERVAL
;
364 put_unaligned_le16(interval_setting
->active_interval
,
365 &set_interval_cmd
.active_interval
);
366 put_unaligned_le16(interval_setting
->lp1_interval
,
367 &set_interval_cmd
.lp1_interval
);
368 put_unaligned_le16(interval_setting
->lp2_interval
,
369 &set_interval_cmd
.lp2_interval
);
371 resp_len
= sizeof(resp_data
);
372 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
373 (u8
*)&set_interval_cmd
, sizeof(set_interval_cmd
),
374 resp_data
, &resp_len
,
375 500, cyapa_sort_tsg_pip_app_resp_data
, false);
377 !VALID_CMD_RESP_HEADER(resp_data
, GEN6_SET_POWER_MODE_INTERVAL
))
378 return error
< 0 ? error
: -EINVAL
;
380 /* Get the real set intervals from response. */
381 interval_setting
->active_interval
= get_unaligned_le16(&resp_data
[5]);
382 interval_setting
->lp1_interval
= get_unaligned_le16(&resp_data
[7]);
383 interval_setting
->lp2_interval
= get_unaligned_le16(&resp_data
[9]);
388 static int cyapa_gen6_get_interval_setting(struct cyapa
*cyapa
,
389 struct gen6_interval_setting
*interval_setting
)
391 u8 cmd
[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00,
392 GEN6_GET_POWER_MODE_INTERVAL
};
397 resp_len
= sizeof(resp_data
);
398 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
, cmd
, sizeof(cmd
),
399 resp_data
, &resp_len
,
400 500, cyapa_sort_tsg_pip_app_resp_data
, false);
402 !VALID_CMD_RESP_HEADER(resp_data
, GEN6_GET_POWER_MODE_INTERVAL
))
403 return error
< 0 ? error
: -EINVAL
;
405 interval_setting
->active_interval
= get_unaligned_le16(&resp_data
[5]);
406 interval_setting
->lp1_interval
= get_unaligned_le16(&resp_data
[7]);
407 interval_setting
->lp2_interval
= get_unaligned_le16(&resp_data
[9]);
412 static int cyapa_gen6_deep_sleep(struct cyapa
*cyapa
, u8 state
)
414 u8 ping
[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 };
416 if (state
== PIP_DEEP_SLEEP_STATE_ON
)
418 * Send ping command to notify device prepare for wake up
419 * when it's in deep sleep mode. At this time, device will
420 * response nothing except an I2C NAK.
422 cyapa_i2c_pip_write(cyapa
, ping
, sizeof(ping
));
424 return cyapa_pip_deep_sleep(cyapa
, state
);
427 static int cyapa_gen6_set_power_mode(struct cyapa
*cyapa
,
428 u8 power_mode
, u16 sleep_time
, enum cyapa_pm_stage pm_stage
)
430 struct device
*dev
= &cyapa
->client
->dev
;
431 struct gen6_interval_setting
*interval_setting
=
432 &cyapa
->gen6_interval_setting
;
436 if (cyapa
->state
!= CYAPA_STATE_GEN6_APP
)
439 if (PIP_DEV_GET_PWR_STATE(cyapa
) == UNINIT_PWR_MODE
) {
441 * Assume TP in deep sleep mode when driver is loaded,
442 * avoid driver unload and reload command IO issue caused by TP
443 * has been set into deep sleep mode when unloading.
445 PIP_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_OFF
);
448 if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa
) &&
449 PIP_DEV_GET_PWR_STATE(cyapa
) != PWR_MODE_OFF
)
450 PIP_DEV_SET_SLEEP_TIME(cyapa
, UNINIT_SLEEP_TIME
);
452 if (PIP_DEV_GET_PWR_STATE(cyapa
) == power_mode
) {
453 if (power_mode
== PWR_MODE_OFF
||
454 power_mode
== PWR_MODE_FULL_ACTIVE
||
455 power_mode
== PWR_MODE_BTN_ONLY
||
456 PIP_DEV_GET_SLEEP_TIME(cyapa
) == sleep_time
) {
457 /* Has in correct power mode state, early return. */
462 if (power_mode
== PWR_MODE_OFF
) {
463 cyapa_gen6_config_dev_irq(cyapa
, GEN6_DISABLE_CMD_IRQ
);
465 error
= cyapa_gen6_deep_sleep(cyapa
, PIP_DEEP_SLEEP_STATE_OFF
);
467 dev_err(dev
, "enter deep sleep fail: %d\n", error
);
471 PIP_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_OFF
);
476 * When trackpad in power off mode, it cannot change to other power
477 * state directly, must be wake up from sleep firstly, then
478 * continue to do next power sate change.
480 if (PIP_DEV_GET_PWR_STATE(cyapa
) == PWR_MODE_OFF
) {
481 error
= cyapa_gen6_deep_sleep(cyapa
, PIP_DEEP_SLEEP_STATE_ON
);
483 dev_err(dev
, "deep sleep wake fail: %d\n", error
);
489 * Disable device assert interrupts for command response to avoid
490 * disturbing system suspending or hibernating process.
492 cyapa_gen6_config_dev_irq(cyapa
, GEN6_DISABLE_CMD_IRQ
);
494 if (power_mode
== PWR_MODE_FULL_ACTIVE
) {
495 error
= cyapa_gen6_change_power_state(cyapa
,
496 GEN6_POWER_MODE_ACTIVE
);
498 dev_err(dev
, "change to active fail: %d\n", error
);
502 PIP_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_FULL_ACTIVE
);
504 /* Sync the interval setting from device. */
505 cyapa_gen6_get_interval_setting(cyapa
, interval_setting
);
507 } else if (power_mode
== PWR_MODE_BTN_ONLY
) {
508 error
= cyapa_gen6_change_power_state(cyapa
,
509 GEN6_POWER_MODE_BTN_ONLY
);
511 dev_err(dev
, "fail to button only mode: %d\n", error
);
515 PIP_DEV_SET_PWR_STATE(cyapa
, PWR_MODE_BTN_ONLY
);
518 * Gen6 internally supports to 2 low power scan interval time,
519 * so can help to switch power mode quickly.
520 * such as runtime suspend and system suspend.
522 if (interval_setting
->lp1_interval
== sleep_time
) {
523 lp_mode
= GEN6_POWER_MODE_LP_MODE1
;
524 } else if (interval_setting
->lp2_interval
== sleep_time
) {
525 lp_mode
= GEN6_POWER_MODE_LP_MODE2
;
527 if (interval_setting
->lp1_interval
== 0) {
528 interval_setting
->lp1_interval
= sleep_time
;
529 lp_mode
= GEN6_POWER_MODE_LP_MODE1
;
531 interval_setting
->lp2_interval
= sleep_time
;
532 lp_mode
= GEN6_POWER_MODE_LP_MODE2
;
534 cyapa_gen6_set_interval_setting(cyapa
,
538 error
= cyapa_gen6_change_power_state(cyapa
, lp_mode
);
540 dev_err(dev
, "set power state to 0x%02x failed: %d\n",
545 PIP_DEV_SET_SLEEP_TIME(cyapa
, sleep_time
);
546 PIP_DEV_SET_PWR_STATE(cyapa
,
547 cyapa_sleep_time_to_pwr_cmd(sleep_time
));
551 cyapa_gen6_config_dev_irq(cyapa
, GEN6_ENABLE_CMD_IRQ
);
555 static int cyapa_gen6_initialize(struct cyapa
*cyapa
)
560 static int cyapa_pip_retrieve_data_structure(struct cyapa
*cyapa
,
561 u16 read_offset
, u16 read_len
, u8 data_id
,
562 u8
*data
, int *data_buf_lens
)
564 struct retrieve_data_struct_cmd
{
565 struct pip_app_cmd_head head
;
570 u8 resp_data
[GEN6_MAX_RX_NUM
+ 10];
574 memset(&cmd
, 0, sizeof(cmd
));
575 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR
, &cmd
.head
.addr
);
576 put_unaligned_le16(sizeof(cmd
), &cmd
.head
.length
- 2);
577 cmd
.head
.report_id
= PIP_APP_CMD_REPORT_ID
;
578 cmd
.head
.cmd_code
= PIP_RETRIEVE_DATA_STRUCTURE
;
579 put_unaligned_le16(read_offset
, &cmd
.read_offset
);
580 put_unaligned_le16(read_len
, &cmd
.read_length
);
581 cmd
.data_id
= data_id
;
583 resp_len
= sizeof(resp_data
);
584 error
= cyapa_i2c_pip_cmd_irq_sync(cyapa
,
585 (u8
*)&cmd
, sizeof(cmd
),
586 resp_data
, &resp_len
,
587 500, cyapa_sort_tsg_pip_app_resp_data
,
589 if (error
|| !PIP_CMD_COMPLETE_SUCCESS(resp_data
) ||
590 resp_data
[6] != data_id
||
591 !VALID_CMD_RESP_HEADER(resp_data
, PIP_RETRIEVE_DATA_STRUCTURE
))
592 return (error
< 0) ? error
: -EAGAIN
;
594 read_len
= get_unaligned_le16(&resp_data
[7]);
595 if (*data_buf_lens
< read_len
) {
596 *data_buf_lens
= read_len
;
600 memcpy(data
, &resp_data
[10], read_len
);
601 *data_buf_lens
= read_len
;
605 static ssize_t
cyapa_gen6_show_baseline(struct device
*dev
,
606 struct device_attribute
*attr
, char *buf
)
608 struct cyapa
*cyapa
= dev_get_drvdata(dev
);
609 u8 data
[GEN6_MAX_RX_NUM
];
616 if (!cyapa_is_pip_app_mode(cyapa
))
619 /* 1. Suspend Scanning*/
620 error
= cyapa_pip_suspend_scanning(cyapa
);
624 /* 2. IDAC and RX Attenuator Calibration Data (Center Frequency). */
625 data_len
= sizeof(data
);
626 error
= cyapa_pip_retrieve_data_structure(cyapa
, 0, data_len
,
627 GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC
,
630 goto resume_scanning
;
632 size
= scnprintf(buf
, PAGE_SIZE
, "%d %d %d %d %d %d ",
633 data
[0], /* RX Attenuator Mutual */
634 data
[1], /* IDAC Mutual */
635 data
[2], /* RX Attenuator Self RX */
636 data
[3], /* IDAC Self RX */
637 data
[4], /* RX Attenuator Self TX */
638 data
[5] /* IDAC Self TX */
641 /* 3. Read Attenuator Trim. */
642 data_len
= sizeof(data
);
643 error
= cyapa_pip_retrieve_data_structure(cyapa
, 0, data_len
,
644 GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM
,
647 goto resume_scanning
;
649 /* set attenuator trim values. */
650 for (i
= 0; i
< data_len
; i
++)
651 size
+= scnprintf(buf
+ size
, PAGE_SIZE
- size
, "%d ", data
[i
]);
652 size
+= scnprintf(buf
+ size
, PAGE_SIZE
- size
, "\n");
655 /* 4. Resume Scanning*/
656 resume_error
= cyapa_pip_resume_scanning(cyapa
);
657 if (resume_error
|| error
) {
658 memset(buf
, 0, PAGE_SIZE
);
659 return resume_error
? resume_error
: error
;
665 static int cyapa_gen6_operational_check(struct cyapa
*cyapa
)
667 struct device
*dev
= &cyapa
->client
->dev
;
670 if (cyapa
->gen
!= CYAPA_GEN6
)
673 switch (cyapa
->state
) {
674 case CYAPA_STATE_GEN6_BL
:
675 error
= cyapa_pip_bl_exit(cyapa
);
677 /* Try to update trackpad product information. */
678 cyapa_gen6_bl_read_app_info(cyapa
);
682 cyapa
->state
= CYAPA_STATE_GEN6_APP
;
685 case CYAPA_STATE_GEN6_APP
:
687 * If trackpad device in deep sleep mode,
688 * the app command will fail.
689 * So always try to reset trackpad device to full active when
690 * the device state is required.
692 error
= cyapa_gen6_set_power_mode(cyapa
,
693 PWR_MODE_FULL_ACTIVE
, 0, CYAPA_PM_ACTIVE
);
695 dev_warn(dev
, "%s: failed to set power active mode.\n",
698 /* By default, the trackpad proximity function is enabled. */
699 error
= cyapa_pip_set_proximity(cyapa
, true);
701 dev_warn(dev
, "%s: failed to enable proximity.\n",
704 /* Get trackpad product information. */
705 error
= cyapa_gen6_read_sys_info(cyapa
);
708 /* Only support product ID starting with CYTRA */
709 if (memcmp(cyapa
->product_id
, product_id
,
710 strlen(product_id
)) != 0) {
711 dev_err(dev
, "%s: unknown product ID (%s)\n",
712 __func__
, cyapa
->product_id
);
724 const struct cyapa_dev_ops cyapa_gen6_ops
= {
725 .check_fw
= cyapa_pip_check_fw
,
726 .bl_enter
= cyapa_pip_bl_enter
,
727 .bl_initiate
= cyapa_pip_bl_initiate
,
728 .update_fw
= cyapa_pip_do_fw_update
,
729 .bl_activate
= cyapa_pip_bl_activate
,
730 .bl_deactivate
= cyapa_pip_bl_deactivate
,
732 .show_baseline
= cyapa_gen6_show_baseline
,
733 .calibrate_store
= cyapa_pip_do_calibrate
,
735 .initialize
= cyapa_gen6_initialize
,
737 .state_parse
= cyapa_pip_state_parse
,
738 .operational_check
= cyapa_gen6_operational_check
,
740 .irq_handler
= cyapa_pip_irq_handler
,
741 .irq_cmd_handler
= cyapa_pip_irq_cmd_handler
,
742 .sort_empty_output_data
= cyapa_empty_pip_output_data
,
743 .set_power_mode
= cyapa_gen6_set_power_mode
,
745 .set_proximity
= cyapa_gen6_set_proximity
,