0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/delay.h>
0014 #include <linux/i2c.h>
0015 #include <linux/input.h>
0016 #include <linux/input/mt.h>
0017 #include <linux/mutex.h>
0018 #include <linux/completion.h>
0019 #include <linux/slab.h>
0020 #include <asm/unaligned.h>
0021 #include <linux/crc-itu-t.h>
0022 #include "cyapa.h"
0023
0024
0025 #define GEN6_ENABLE_CMD_IRQ 0x41
0026 #define GEN6_DISABLE_CMD_IRQ 0x42
0027 #define GEN6_ENABLE_DEV_IRQ 0x43
0028 #define GEN6_DISABLE_DEV_IRQ 0x44
0029
0030 #define GEN6_POWER_MODE_ACTIVE 0x01
0031 #define GEN6_POWER_MODE_LP_MODE1 0x02
0032 #define GEN6_POWER_MODE_LP_MODE2 0x03
0033 #define GEN6_POWER_MODE_BTN_ONLY 0x04
0034
0035 #define GEN6_SET_POWER_MODE_INTERVAL 0x47
0036 #define GEN6_GET_POWER_MODE_INTERVAL 0x48
0037
0038 #define GEN6_MAX_RX_NUM 14
0039 #define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00
0040 #define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12
0041
0042
0043 struct pip_app_cmd_head {
0044 __le16 addr;
0045 __le16 length;
0046 u8 report_id;
0047 u8 resv;
0048 u8 cmd_code;
0049 } __packed;
0050
0051 struct pip_app_resp_head {
0052 __le16 length;
0053 u8 report_id;
0054 u8 resv;
0055 u8 cmd_code;
0056
0057
0058
0059
0060
0061 u8 data_status;
0062 } __packed;
0063
0064 struct pip_fixed_info {
0065 u8 silicon_id_high;
0066 u8 silicon_id_low;
0067 u8 family_id;
0068 };
0069
0070 static u8 pip_get_bl_info[] = {
0071 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
0072 0x00, 0x00, 0x70, 0x9E, 0x17
0073 };
0074
0075 static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa,
0076 u8 *buf, int len)
0077 {
0078 if (len != PIP_HID_DESCRIPTOR_SIZE)
0079 return false;
0080
0081 if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID ||
0082 buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)
0083 return true;
0084
0085 return false;
0086 }
0087
0088 static int cyapa_get_pip_fixed_info(struct cyapa *cyapa,
0089 struct pip_fixed_info *pip_info, bool is_bootloader)
0090 {
0091 u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
0092 int resp_len;
0093 u16 product_family;
0094 int error;
0095
0096 if (is_bootloader) {
0097
0098 resp_len = sizeof(resp_data);
0099 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0100 pip_get_bl_info, sizeof(pip_get_bl_info),
0101 resp_data, &resp_len,
0102 2000, cyapa_sort_tsg_pip_bl_resp_data,
0103 false);
0104 if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH)
0105 return error ? error : -EIO;
0106
0107 pip_info->family_id = resp_data[8];
0108 pip_info->silicon_id_low = resp_data[10];
0109 pip_info->silicon_id_high = resp_data[11];
0110
0111 return 0;
0112 }
0113
0114
0115 resp_len = sizeof(resp_data);
0116 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0117 pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
0118 resp_data, &resp_len,
0119 2000, cyapa_pip_sort_system_info_data, false);
0120 if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH)
0121 return error ? error : -EIO;
0122
0123 product_family = get_unaligned_le16(&resp_data[7]);
0124 if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
0125 PIP_PRODUCT_FAMILY_TRACKPAD)
0126 return -EINVAL;
0127
0128 pip_info->family_id = resp_data[19];
0129 pip_info->silicon_id_low = resp_data[21];
0130 pip_info->silicon_id_high = resp_data[22];
0131
0132 return 0;
0133
0134 }
0135
0136 int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
0137 {
0138 u8 cmd[] = { 0x01, 0x00};
0139 struct pip_fixed_info pip_info;
0140 u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
0141 int resp_len;
0142 bool is_bootloader;
0143 int error;
0144
0145 cyapa->state = CYAPA_STATE_NO_DEVICE;
0146
0147
0148 cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
0149
0150
0151 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
0152
0153
0154
0155
0156
0157 resp_len = PIP_HID_DESCRIPTOR_SIZE;
0158 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0159 cmd, sizeof(cmd),
0160 resp_data, &resp_len,
0161 300,
0162 cyapa_sort_pip_hid_descriptor_data,
0163 false);
0164 if (error)
0165 return error;
0166
0167 if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)
0168 is_bootloader = true;
0169 else if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID)
0170 is_bootloader = false;
0171 else
0172 return -EAGAIN;
0173
0174
0175 memset(&pip_info, 0, sizeof(struct pip_fixed_info));
0176 error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader);
0177 if (error)
0178 return error;
0179
0180 if (pip_info.family_id == 0x9B && pip_info.silicon_id_high == 0x0B) {
0181 cyapa->gen = CYAPA_GEN6;
0182 cyapa->state = is_bootloader ? CYAPA_STATE_GEN6_BL
0183 : CYAPA_STATE_GEN6_APP;
0184 } else if (pip_info.family_id == 0x91 &&
0185 pip_info.silicon_id_high == 0x02) {
0186 cyapa->gen = CYAPA_GEN5;
0187 cyapa->state = is_bootloader ? CYAPA_STATE_GEN5_BL
0188 : CYAPA_STATE_GEN5_APP;
0189 }
0190
0191 return 0;
0192 }
0193
0194 static int cyapa_gen6_read_sys_info(struct cyapa *cyapa)
0195 {
0196 u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
0197 int resp_len;
0198 u16 product_family;
0199 u8 rotat_align;
0200 int error;
0201
0202
0203 resp_len = sizeof(resp_data);
0204 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0205 pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,
0206 resp_data, &resp_len,
0207 2000, cyapa_pip_sort_system_info_data, false);
0208 if (error || resp_len < sizeof(resp_data))
0209 return error ? error : -EIO;
0210
0211 product_family = get_unaligned_le16(&resp_data[7]);
0212 if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
0213 PIP_PRODUCT_FAMILY_TRACKPAD)
0214 return -EINVAL;
0215
0216 cyapa->platform_ver = (resp_data[67] >> PIP_BL_PLATFORM_VER_SHIFT) &
0217 PIP_BL_PLATFORM_VER_MASK;
0218 cyapa->fw_maj_ver = resp_data[9];
0219 cyapa->fw_min_ver = resp_data[10];
0220
0221 cyapa->electrodes_x = resp_data[33];
0222 cyapa->electrodes_y = resp_data[34];
0223
0224 cyapa->physical_size_x = get_unaligned_le16(&resp_data[35]) / 100;
0225 cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100;
0226
0227 cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]);
0228 cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]);
0229
0230 cyapa->max_z = get_unaligned_le16(&resp_data[43]);
0231
0232 cyapa->x_origin = resp_data[45] & 0x01;
0233 cyapa->y_origin = resp_data[46] & 0x01;
0234
0235 cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
0236
0237 memcpy(&cyapa->product_id[0], &resp_data[51], 5);
0238 cyapa->product_id[5] = '-';
0239 memcpy(&cyapa->product_id[6], &resp_data[56], 6);
0240 cyapa->product_id[12] = '-';
0241 memcpy(&cyapa->product_id[13], &resp_data[62], 2);
0242 cyapa->product_id[15] = '\0';
0243
0244
0245 rotat_align = resp_data[68];
0246 cyapa->electrodes_rx =
0247 rotat_align ? cyapa->electrodes_y : cyapa->electrodes_x;
0248 cyapa->aligned_electrodes_rx = (cyapa->electrodes_rx + 3) & ~3u;
0249
0250 if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
0251 !cyapa->physical_size_x || !cyapa->physical_size_y ||
0252 !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
0253 return -EINVAL;
0254
0255 return 0;
0256 }
0257
0258 static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa)
0259 {
0260 u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH];
0261 int resp_len;
0262 int error;
0263
0264 resp_len = sizeof(resp_data);
0265 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0266 pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH,
0267 resp_data, &resp_len,
0268 500, cyapa_sort_tsg_pip_bl_resp_data, false);
0269 if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH ||
0270 !PIP_CMD_COMPLETE_SUCCESS(resp_data))
0271 return error ? error : -EIO;
0272
0273 cyapa->fw_maj_ver = resp_data[8];
0274 cyapa->fw_min_ver = resp_data[9];
0275
0276 cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) &
0277 PIP_BL_PLATFORM_VER_MASK;
0278
0279 memcpy(&cyapa->product_id[0], &resp_data[13], 5);
0280 cyapa->product_id[5] = '-';
0281 memcpy(&cyapa->product_id[6], &resp_data[18], 6);
0282 cyapa->product_id[12] = '-';
0283 memcpy(&cyapa->product_id[13], &resp_data[24], 2);
0284 cyapa->product_id[15] = '\0';
0285
0286 return 0;
0287
0288 }
0289
0290 static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code)
0291 {
0292 u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code };
0293 u8 resp_data[6];
0294 int resp_len;
0295 int error;
0296
0297 resp_len = sizeof(resp_data);
0298 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
0299 resp_data, &resp_len,
0300 500, cyapa_sort_tsg_pip_app_resp_data, false);
0301 if (error || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
0302 !PIP_CMD_COMPLETE_SUCCESS(resp_data)
0303 )
0304 return error < 0 ? error : -EINVAL;
0305
0306 return 0;
0307 }
0308
0309 static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable)
0310 {
0311 int error;
0312
0313 cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
0314 error = cyapa_pip_set_proximity(cyapa, enable);
0315 cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
0316
0317 return error;
0318 }
0319
0320 static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode)
0321 {
0322 u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode };
0323 u8 resp_data[6];
0324 int resp_len;
0325 int error;
0326
0327 resp_len = sizeof(resp_data);
0328 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
0329 resp_data, &resp_len,
0330 500, cyapa_sort_tsg_pip_app_resp_data, false);
0331 if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x46))
0332 return error < 0 ? error : -EINVAL;
0333
0334
0335 if (resp_data[5] != power_mode)
0336 return -EAGAIN;
0337
0338 return 0;
0339 }
0340
0341 static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa,
0342 struct gen6_interval_setting *interval_setting)
0343 {
0344 struct gen6_set_interval_cmd {
0345 __le16 addr;
0346 __le16 length;
0347 u8 report_id;
0348 u8 rsvd;
0349 u8 cmd_code;
0350 __le16 active_interval;
0351 __le16 lp1_interval;
0352 __le16 lp2_interval;
0353 } __packed set_interval_cmd;
0354 u8 resp_data[11];
0355 int resp_len;
0356 int error;
0357
0358 memset(&set_interval_cmd, 0, sizeof(set_interval_cmd));
0359 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &set_interval_cmd.addr);
0360 put_unaligned_le16(sizeof(set_interval_cmd) - 2,
0361 &set_interval_cmd.length);
0362 set_interval_cmd.report_id = PIP_APP_CMD_REPORT_ID;
0363 set_interval_cmd.cmd_code = GEN6_SET_POWER_MODE_INTERVAL;
0364 put_unaligned_le16(interval_setting->active_interval,
0365 &set_interval_cmd.active_interval);
0366 put_unaligned_le16(interval_setting->lp1_interval,
0367 &set_interval_cmd.lp1_interval);
0368 put_unaligned_le16(interval_setting->lp2_interval,
0369 &set_interval_cmd.lp2_interval);
0370
0371 resp_len = sizeof(resp_data);
0372 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0373 (u8 *)&set_interval_cmd, sizeof(set_interval_cmd),
0374 resp_data, &resp_len,
0375 500, cyapa_sort_tsg_pip_app_resp_data, false);
0376 if (error ||
0377 !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL))
0378 return error < 0 ? error : -EINVAL;
0379
0380
0381 interval_setting->active_interval = get_unaligned_le16(&resp_data[5]);
0382 interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]);
0383 interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]);
0384
0385 return 0;
0386 }
0387
0388 static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa,
0389 struct gen6_interval_setting *interval_setting)
0390 {
0391 u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00,
0392 GEN6_GET_POWER_MODE_INTERVAL };
0393 u8 resp_data[11];
0394 int resp_len;
0395 int error;
0396
0397 resp_len = sizeof(resp_data);
0398 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
0399 resp_data, &resp_len,
0400 500, cyapa_sort_tsg_pip_app_resp_data, false);
0401 if (error ||
0402 !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL))
0403 return error < 0 ? error : -EINVAL;
0404
0405 interval_setting->active_interval = get_unaligned_le16(&resp_data[5]);
0406 interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]);
0407 interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]);
0408
0409 return 0;
0410 }
0411
0412 static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state)
0413 {
0414 u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 };
0415
0416 if (state == PIP_DEEP_SLEEP_STATE_ON)
0417
0418
0419
0420
0421
0422 cyapa_i2c_pip_write(cyapa, ping, sizeof(ping));
0423
0424 return cyapa_pip_deep_sleep(cyapa, state);
0425 }
0426
0427 static int cyapa_gen6_set_power_mode(struct cyapa *cyapa,
0428 u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
0429 {
0430 struct device *dev = &cyapa->client->dev;
0431 struct gen6_interval_setting *interval_setting =
0432 &cyapa->gen6_interval_setting;
0433 u8 lp_mode;
0434 int error;
0435
0436 if (cyapa->state != CYAPA_STATE_GEN6_APP)
0437 return 0;
0438
0439 if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
0440
0441
0442
0443
0444
0445 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
0446 }
0447
0448 if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) &&
0449 PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
0450 PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
0451
0452 if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) {
0453 if (power_mode == PWR_MODE_OFF ||
0454 power_mode == PWR_MODE_FULL_ACTIVE ||
0455 power_mode == PWR_MODE_BTN_ONLY ||
0456 PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
0457
0458 return 0;
0459 }
0460 }
0461
0462 if (power_mode == PWR_MODE_OFF) {
0463 cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
0464
0465 error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
0466 if (error) {
0467 dev_err(dev, "enter deep sleep fail: %d\n", error);
0468 return error;
0469 }
0470
0471 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
0472 return 0;
0473 }
0474
0475
0476
0477
0478
0479
0480 if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
0481 error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
0482 if (error) {
0483 dev_err(dev, "deep sleep wake fail: %d\n", error);
0484 return error;
0485 }
0486 }
0487
0488
0489
0490
0491
0492 cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
0493
0494 if (power_mode == PWR_MODE_FULL_ACTIVE) {
0495 error = cyapa_gen6_change_power_state(cyapa,
0496 GEN6_POWER_MODE_ACTIVE);
0497 if (error) {
0498 dev_err(dev, "change to active fail: %d\n", error);
0499 goto out;
0500 }
0501
0502 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
0503
0504
0505 cyapa_gen6_get_interval_setting(cyapa, interval_setting);
0506
0507 } else if (power_mode == PWR_MODE_BTN_ONLY) {
0508 error = cyapa_gen6_change_power_state(cyapa,
0509 GEN6_POWER_MODE_BTN_ONLY);
0510 if (error) {
0511 dev_err(dev, "fail to button only mode: %d\n", error);
0512 goto out;
0513 }
0514
0515 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
0516 } else {
0517
0518
0519
0520
0521
0522 if (interval_setting->lp1_interval == sleep_time) {
0523 lp_mode = GEN6_POWER_MODE_LP_MODE1;
0524 } else if (interval_setting->lp2_interval == sleep_time) {
0525 lp_mode = GEN6_POWER_MODE_LP_MODE2;
0526 } else {
0527 if (interval_setting->lp1_interval == 0) {
0528 interval_setting->lp1_interval = sleep_time;
0529 lp_mode = GEN6_POWER_MODE_LP_MODE1;
0530 } else {
0531 interval_setting->lp2_interval = sleep_time;
0532 lp_mode = GEN6_POWER_MODE_LP_MODE2;
0533 }
0534 cyapa_gen6_set_interval_setting(cyapa,
0535 interval_setting);
0536 }
0537
0538 error = cyapa_gen6_change_power_state(cyapa, lp_mode);
0539 if (error) {
0540 dev_err(dev, "set power state to 0x%02x failed: %d\n",
0541 lp_mode, error);
0542 goto out;
0543 }
0544
0545 PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
0546 PIP_DEV_SET_PWR_STATE(cyapa,
0547 cyapa_sleep_time_to_pwr_cmd(sleep_time));
0548 }
0549
0550 out:
0551 cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
0552 return error;
0553 }
0554
0555 static int cyapa_gen6_initialize(struct cyapa *cyapa)
0556 {
0557 return 0;
0558 }
0559
0560 static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa,
0561 u16 read_offset, u16 read_len, u8 data_id,
0562 u8 *data, int *data_buf_lens)
0563 {
0564 struct retrieve_data_struct_cmd {
0565 struct pip_app_cmd_head head;
0566 __le16 read_offset;
0567 __le16 read_length;
0568 u8 data_id;
0569 } __packed cmd;
0570 u8 resp_data[GEN6_MAX_RX_NUM + 10];
0571 int resp_len;
0572 int error;
0573
0574 memset(&cmd, 0, sizeof(cmd));
0575 put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr);
0576 put_unaligned_le16(sizeof(cmd) - 2, &cmd.head.length);
0577 cmd.head.report_id = PIP_APP_CMD_REPORT_ID;
0578 cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE;
0579 put_unaligned_le16(read_offset, &cmd.read_offset);
0580 put_unaligned_le16(read_len, &cmd.read_length);
0581 cmd.data_id = data_id;
0582
0583 resp_len = sizeof(resp_data);
0584 error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
0585 (u8 *)&cmd, sizeof(cmd),
0586 resp_data, &resp_len,
0587 500, cyapa_sort_tsg_pip_app_resp_data,
0588 true);
0589 if (error || !PIP_CMD_COMPLETE_SUCCESS(resp_data) ||
0590 resp_data[6] != data_id ||
0591 !VALID_CMD_RESP_HEADER(resp_data, PIP_RETRIEVE_DATA_STRUCTURE))
0592 return (error < 0) ? error : -EAGAIN;
0593
0594 read_len = get_unaligned_le16(&resp_data[7]);
0595 if (*data_buf_lens < read_len) {
0596 *data_buf_lens = read_len;
0597 return -ENOBUFS;
0598 }
0599
0600 memcpy(data, &resp_data[10], read_len);
0601 *data_buf_lens = read_len;
0602 return 0;
0603 }
0604
0605 static ssize_t cyapa_gen6_show_baseline(struct device *dev,
0606 struct device_attribute *attr, char *buf)
0607 {
0608 struct cyapa *cyapa = dev_get_drvdata(dev);
0609 u8 data[GEN6_MAX_RX_NUM];
0610 int data_len;
0611 int size = 0;
0612 int i;
0613 int error;
0614 int resume_error;
0615
0616 if (!cyapa_is_pip_app_mode(cyapa))
0617 return -EBUSY;
0618
0619
0620 error = cyapa_pip_suspend_scanning(cyapa);
0621 if (error)
0622 return error;
0623
0624
0625 data_len = sizeof(data);
0626 error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len,
0627 GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC,
0628 data, &data_len);
0629 if (error)
0630 goto resume_scanning;
0631
0632 size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ",
0633 data[0],
0634 data[1],
0635 data[2],
0636 data[3],
0637 data[4],
0638 data[5]
0639 );
0640
0641
0642 data_len = sizeof(data);
0643 error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len,
0644 GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM,
0645 data, &data_len);
0646 if (error)
0647 goto resume_scanning;
0648
0649
0650 for (i = 0; i < data_len; i++)
0651 size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]);
0652 size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
0653
0654 resume_scanning:
0655
0656 resume_error = cyapa_pip_resume_scanning(cyapa);
0657 if (resume_error || error) {
0658 memset(buf, 0, PAGE_SIZE);
0659 return resume_error ? resume_error : error;
0660 }
0661
0662 return size;
0663 }
0664
0665 static int cyapa_gen6_operational_check(struct cyapa *cyapa)
0666 {
0667 struct device *dev = &cyapa->client->dev;
0668 int error;
0669
0670 if (cyapa->gen != CYAPA_GEN6)
0671 return -ENODEV;
0672
0673 switch (cyapa->state) {
0674 case CYAPA_STATE_GEN6_BL:
0675 error = cyapa_pip_bl_exit(cyapa);
0676 if (error) {
0677
0678 cyapa_gen6_bl_read_app_info(cyapa);
0679 goto out;
0680 }
0681
0682 cyapa->state = CYAPA_STATE_GEN6_APP;
0683 fallthrough;
0684
0685 case CYAPA_STATE_GEN6_APP:
0686
0687
0688
0689
0690
0691
0692 error = cyapa_gen6_set_power_mode(cyapa,
0693 PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
0694 if (error)
0695 dev_warn(dev, "%s: failed to set power active mode.\n",
0696 __func__);
0697
0698
0699 error = cyapa_pip_set_proximity(cyapa, true);
0700 if (error)
0701 dev_warn(dev, "%s: failed to enable proximity.\n",
0702 __func__);
0703
0704
0705 error = cyapa_gen6_read_sys_info(cyapa);
0706 if (error)
0707 goto out;
0708
0709 if (memcmp(cyapa->product_id, product_id,
0710 strlen(product_id)) != 0) {
0711 dev_err(dev, "%s: unknown product ID (%s)\n",
0712 __func__, cyapa->product_id);
0713 error = -EINVAL;
0714 }
0715 break;
0716 default:
0717 error = -EINVAL;
0718 }
0719
0720 out:
0721 return error;
0722 }
0723
0724 const struct cyapa_dev_ops cyapa_gen6_ops = {
0725 .check_fw = cyapa_pip_check_fw,
0726 .bl_enter = cyapa_pip_bl_enter,
0727 .bl_initiate = cyapa_pip_bl_initiate,
0728 .update_fw = cyapa_pip_do_fw_update,
0729 .bl_activate = cyapa_pip_bl_activate,
0730 .bl_deactivate = cyapa_pip_bl_deactivate,
0731
0732 .show_baseline = cyapa_gen6_show_baseline,
0733 .calibrate_store = cyapa_pip_do_calibrate,
0734
0735 .initialize = cyapa_gen6_initialize,
0736
0737 .state_parse = cyapa_pip_state_parse,
0738 .operational_check = cyapa_gen6_operational_check,
0739
0740 .irq_handler = cyapa_pip_irq_handler,
0741 .irq_cmd_handler = cyapa_pip_irq_cmd_handler,
0742 .sort_empty_output_data = cyapa_empty_pip_output_data,
0743 .set_power_mode = cyapa_gen6_set_power_mode,
0744
0745 .set_proximity = cyapa_gen6_set_proximity,
0746 };