root/drivers/input/mouse/cyapa_gen6.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cyapa_sort_pip_hid_descriptor_data
  2. cyapa_get_pip_fixed_info
  3. cyapa_pip_state_parse
  4. cyapa_gen6_read_sys_info
  5. cyapa_gen6_bl_read_app_info
  6. cyapa_gen6_config_dev_irq
  7. cyapa_gen6_set_proximity
  8. cyapa_gen6_change_power_state
  9. cyapa_gen6_set_interval_setting
  10. cyapa_gen6_get_interval_setting
  11. cyapa_gen6_deep_sleep
  12. cyapa_gen6_set_power_mode
  13. cyapa_gen6_initialize
  14. cyapa_pip_retrieve_data_structure
  15. cyapa_gen6_show_baseline
  16. cyapa_gen6_operational_check

   1 /*
   2  * Cypress APA trackpad with I2C interface
   3  *
   4  * Author: Dudley Du <dudl@cypress.com>
   5  *
   6  * Copyright (C) 2015 Cypress Semiconductor, Inc.
   7  *
   8  * This file is subject to the terms and conditions of the GNU General Public
   9  * License.  See the file COPYING in the main directory of this archive for
  10  * more details.
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/i2c.h>
  15 #include <linux/input.h>
  16 #include <linux/input/mt.h>
  17 #include <linux/mutex.h>
  18 #include <linux/completion.h>
  19 #include <linux/slab.h>
  20 #include <asm/unaligned.h>
  21 #include <linux/crc-itu-t.h>
  22 #include "cyapa.h"
  23 
  24 
  25 #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
  29 
  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
  34 
  35 #define GEN6_SET_POWER_MODE_INTERVAL    0x47
  36 #define GEN6_GET_POWER_MODE_INTERVAL    0x48
  37 
  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
  41 
  42 
  43 struct pip_app_cmd_head {
  44         __le16 addr;
  45         __le16 length;
  46         u8 report_id;
  47         u8 resv;  /* Reserved, must be 0 */
  48         u8 cmd_code;  /* bit7: resv, set to 0; bit6~0: command code.*/
  49 } __packed;
  50 
  51 struct pip_app_resp_head {
  52         __le16 length;
  53         u8 report_id;
  54         u8 resv;  /* Reserved, must be 0 */
  55         u8 cmd_code;  /* bit7: TGL; bit6~0: command code.*/
  56         /*
  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.
  60         */
  61         u8 data_status;
  62 } __packed;
  63 
  64 struct pip_fixed_info {
  65         u8 silicon_id_high;
  66         u8 silicon_id_low;
  67         u8 family_id;
  68 };
  69 
  70 static u8 pip_get_bl_info[] = {
  71         0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
  72         0x00, 0x00, 0x70, 0x9E, 0x17
  73 };
  74 
  75 static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa,
  76                 u8 *buf, int len)
  77 {
  78         if (len != PIP_HID_DESCRIPTOR_SIZE)
  79                 return false;
  80 
  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)
  83                 return true;
  84 
  85         return false;
  86 }
  87 
  88 static int cyapa_get_pip_fixed_info(struct cyapa *cyapa,
  89                 struct pip_fixed_info *pip_info, bool is_bootloader)
  90 {
  91         u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
  92         int resp_len;
  93         u16 product_family;
  94         int error;
  95 
  96         if (is_bootloader) {
  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,
 103                                 false);
 104                 if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH)
 105                         return error ? error : -EIO;
 106 
 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];
 110 
 111                 return 0;
 112         }
 113 
 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;
 122 
 123         product_family = get_unaligned_le16(&resp_data[7]);
 124         if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
 125                 PIP_PRODUCT_FAMILY_TRACKPAD)
 126                 return -EINVAL;
 127 
 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];
 131 
 132         return 0;
 133 
 134 }
 135 
 136 int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
 137 {
 138         u8 cmd[] = { 0x01, 0x00};
 139         struct pip_fixed_info pip_info;
 140         u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
 141         int resp_len;
 142         bool is_bootloader;
 143         int error;
 144 
 145         cyapa->state = CYAPA_STATE_NO_DEVICE;
 146 
 147         /* Try to wake from it deep sleep state if it is. */
 148         cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
 149 
 150         /* Empty the buffer queue to get fresh data with later commands. */
 151         cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
 152 
 153         /*
 154          * Read description info from trackpad device to determine running in
 155          * APP mode or Bootloader mode.
 156          */
 157         resp_len = PIP_HID_DESCRIPTOR_SIZE;
 158         error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
 159                         cmd, sizeof(cmd),
 160                         resp_data, &resp_len,
 161                         300,
 162                         cyapa_sort_pip_hid_descriptor_data,
 163                         false);
 164         if (error)
 165                 return error;
 166 
 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;
 171         else
 172                 return -EAGAIN;
 173 
 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);
 177         if (error)
 178                 return error;
 179 
 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;
 189         }
 190 
 191         return 0;
 192 }
 193 
 194 static int cyapa_gen6_read_sys_info(struct cyapa *cyapa)
 195 {
 196         u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
 197         int resp_len;
 198         u16 product_family;
 199         u8 rotat_align;
 200         int error;
 201 
 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;
 210 
 211         product_family = get_unaligned_le16(&resp_data[7]);
 212         if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=
 213                 PIP_PRODUCT_FAMILY_TRACKPAD)
 214                 return -EINVAL;
 215 
 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];
 220 
 221         cyapa->electrodes_x = resp_data[33];
 222         cyapa->electrodes_y = resp_data[34];
 223 
 224         cyapa->physical_size_x =  get_unaligned_le16(&resp_data[35]) / 100;
 225         cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100;
 226 
 227         cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]);
 228         cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]);
 229 
 230         cyapa->max_z = get_unaligned_le16(&resp_data[43]);
 231 
 232         cyapa->x_origin = resp_data[45] & 0x01;
 233         cyapa->y_origin = resp_data[46] & 0x01;
 234 
 235         cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
 236 
 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';
 243 
 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;
 249 
 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)
 253                 return -EINVAL;
 254 
 255         return 0;
 256 }
 257 
 258 static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa)
 259 {
 260         u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH];
 261         int resp_len;
 262         int error;
 263 
 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;
 272 
 273         cyapa->fw_maj_ver = resp_data[8];
 274         cyapa->fw_min_ver = resp_data[9];
 275 
 276         cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) &
 277                               PIP_BL_PLATFORM_VER_MASK;
 278 
 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';
 285 
 286         return 0;
 287 
 288 }
 289 
 290 static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code)
 291 {
 292         u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code };
 293         u8 resp_data[6];
 294         int resp_len;
 295         int error;
 296 
 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)
 303                         )
 304                 return error < 0 ? error : -EINVAL;
 305 
 306         return 0;
 307 }
 308 
 309 static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable)
 310 {
 311         int error;
 312 
 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);
 316 
 317         return error;
 318 }
 319 
 320 static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode)
 321 {
 322         u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode };
 323         u8 resp_data[6];
 324         int resp_len;
 325         int error;
 326 
 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;
 333 
 334         /* New power state applied in device not match the set power state. */
 335         if (resp_data[5] != power_mode)
 336                 return -EAGAIN;
 337 
 338         return 0;
 339 }
 340 
 341 static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa,
 342                 struct gen6_interval_setting *interval_setting)
 343 {
 344         struct gen6_set_interval_cmd {
 345                 __le16 addr;
 346                 __le16 length;
 347                 u8 report_id;
 348                 u8 rsvd;  /* Reserved, must be 0 */
 349                 u8 cmd_code;
 350                 __le16 active_interval;
 351                 __le16 lp1_interval;
 352                 __le16 lp2_interval;
 353         } __packed set_interval_cmd;
 354         u8 resp_data[11];
 355         int resp_len;
 356         int error;
 357 
 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);
 370 
 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);
 376         if (error ||
 377                 !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL))
 378                 return error < 0 ? error : -EINVAL;
 379 
 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]);
 384 
 385         return 0;
 386 }
 387 
 388 static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa,
 389                 struct gen6_interval_setting *interval_setting)
 390 {
 391         u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00,
 392                      GEN6_GET_POWER_MODE_INTERVAL };
 393         u8 resp_data[11];
 394         int resp_len;
 395         int error;
 396 
 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);
 401         if (error ||
 402                 !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL))
 403                 return error < 0 ? error : -EINVAL;
 404 
 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]);
 408 
 409         return 0;
 410 }
 411 
 412 static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state)
 413 {
 414         u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 };
 415 
 416         if (state == PIP_DEEP_SLEEP_STATE_ON)
 417                 /*
 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.
 421                  */
 422                 cyapa_i2c_pip_write(cyapa, ping, sizeof(ping));
 423 
 424         return cyapa_pip_deep_sleep(cyapa, state);
 425 }
 426 
 427 static int cyapa_gen6_set_power_mode(struct cyapa *cyapa,
 428                 u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
 429 {
 430         struct device *dev = &cyapa->client->dev;
 431         struct gen6_interval_setting *interval_setting =
 432                         &cyapa->gen6_interval_setting;
 433         u8 lp_mode;
 434         int error;
 435 
 436         if (cyapa->state != CYAPA_STATE_GEN6_APP)
 437                 return 0;
 438 
 439         if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
 440                 /*
 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.
 444                  */
 445                 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
 446         }
 447 
 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);
 451 
 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. */
 458                         return 0;
 459                 }
 460         }
 461 
 462         if (power_mode == PWR_MODE_OFF) {
 463                 cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
 464 
 465                 error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
 466                 if (error) {
 467                         dev_err(dev, "enter deep sleep fail: %d\n", error);
 468                         return error;
 469                 }
 470 
 471                 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
 472                 return 0;
 473         }
 474 
 475         /*
 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.
 479          */
 480         if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
 481                 error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
 482                 if (error) {
 483                         dev_err(dev, "deep sleep wake fail: %d\n", error);
 484                         return error;
 485                 }
 486         }
 487 
 488         /*
 489          * Disable device assert interrupts for command response to avoid
 490          * disturbing system suspending or hibernating process.
 491          */
 492         cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
 493 
 494         if (power_mode == PWR_MODE_FULL_ACTIVE) {
 495                 error = cyapa_gen6_change_power_state(cyapa,
 496                                 GEN6_POWER_MODE_ACTIVE);
 497                 if (error) {
 498                         dev_err(dev, "change to active fail: %d\n", error);
 499                         goto out;
 500                 }
 501 
 502                 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
 503 
 504                 /* Sync the interval setting from device. */
 505                 cyapa_gen6_get_interval_setting(cyapa, interval_setting);
 506 
 507         } else if (power_mode == PWR_MODE_BTN_ONLY) {
 508                 error = cyapa_gen6_change_power_state(cyapa,
 509                                 GEN6_POWER_MODE_BTN_ONLY);
 510                 if (error) {
 511                         dev_err(dev, "fail to button only mode: %d\n", error);
 512                         goto out;
 513                 }
 514 
 515                 PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
 516         } else {
 517                 /*
 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.
 521                  */
 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;
 526                 } else {
 527                         if (interval_setting->lp1_interval == 0) {
 528                                 interval_setting->lp1_interval = sleep_time;
 529                                 lp_mode = GEN6_POWER_MODE_LP_MODE1;
 530                         } else {
 531                                 interval_setting->lp2_interval = sleep_time;
 532                                 lp_mode = GEN6_POWER_MODE_LP_MODE2;
 533                         }
 534                         cyapa_gen6_set_interval_setting(cyapa,
 535                                                         interval_setting);
 536                 }
 537 
 538                 error = cyapa_gen6_change_power_state(cyapa, lp_mode);
 539                 if (error) {
 540                         dev_err(dev, "set power state to 0x%02x failed: %d\n",
 541                                 lp_mode, error);
 542                         goto out;
 543                 }
 544 
 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));
 548         }
 549 
 550 out:
 551         cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
 552         return error;
 553 }
 554 
 555 static int cyapa_gen6_initialize(struct cyapa *cyapa)
 556 {
 557         return 0;
 558 }
 559 
 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)
 563 {
 564         struct retrieve_data_struct_cmd {
 565                 struct pip_app_cmd_head head;
 566                 __le16 read_offset;
 567                 __le16 read_length;
 568                 u8 data_id;
 569         } __packed cmd;
 570         u8 resp_data[GEN6_MAX_RX_NUM + 10];
 571         int resp_len;
 572         int error;
 573 
 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;
 582 
 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,
 588                                 true);
 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;
 593 
 594         read_len = get_unaligned_le16(&resp_data[7]);
 595         if (*data_buf_lens < read_len) {
 596                 *data_buf_lens = read_len;
 597                 return -ENOBUFS;
 598         }
 599 
 600         memcpy(data, &resp_data[10], read_len);
 601         *data_buf_lens = read_len;
 602         return 0;
 603 }
 604 
 605 static ssize_t cyapa_gen6_show_baseline(struct device *dev,
 606                 struct device_attribute *attr, char *buf)
 607 {
 608         struct cyapa *cyapa = dev_get_drvdata(dev);
 609         u8 data[GEN6_MAX_RX_NUM];
 610         int data_len;
 611         int size = 0;
 612         int i;
 613         int error;
 614         int resume_error;
 615 
 616         if (!cyapa_is_pip_app_mode(cyapa))
 617                 return -EBUSY;
 618 
 619         /* 1. Suspend Scanning*/
 620         error = cyapa_pip_suspend_scanning(cyapa);
 621         if (error)
 622                 return error;
 623 
 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,
 628                         data, &data_len);
 629         if (error)
 630                 goto resume_scanning;
 631 
 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 */
 639                         );
 640 
 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,
 645                         data, &data_len);
 646         if (error)
 647                 goto resume_scanning;
 648 
 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");
 653 
 654 resume_scanning:
 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;
 660         }
 661 
 662         return size;
 663 }
 664 
 665 static int cyapa_gen6_operational_check(struct cyapa *cyapa)
 666 {
 667         struct device *dev = &cyapa->client->dev;
 668         int error;
 669 
 670         if (cyapa->gen != CYAPA_GEN6)
 671                 return -ENODEV;
 672 
 673         switch (cyapa->state) {
 674         case CYAPA_STATE_GEN6_BL:
 675                 error = cyapa_pip_bl_exit(cyapa);
 676                 if (error) {
 677                         /* Try to update trackpad product information. */
 678                         cyapa_gen6_bl_read_app_info(cyapa);
 679                         goto out;
 680                 }
 681 
 682                 cyapa->state = CYAPA_STATE_GEN6_APP;
 683                 /* fall through */
 684 
 685         case CYAPA_STATE_GEN6_APP:
 686                 /*
 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.
 691                  */
 692                 error = cyapa_gen6_set_power_mode(cyapa,
 693                                 PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
 694                 if (error)
 695                         dev_warn(dev, "%s: failed to set power active mode.\n",
 696                                 __func__);
 697 
 698                 /* By default, the trackpad proximity function is enabled. */
 699                 error = cyapa_pip_set_proximity(cyapa, true);
 700                 if (error)
 701                         dev_warn(dev, "%s: failed to enable proximity.\n",
 702                                 __func__);
 703 
 704                 /* Get trackpad product information. */
 705                 error = cyapa_gen6_read_sys_info(cyapa);
 706                 if (error)
 707                         goto out;
 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);
 713                         error = -EINVAL;
 714                 }
 715                 break;
 716         default:
 717                 error = -EINVAL;
 718         }
 719 
 720 out:
 721         return error;
 722 }
 723 
 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,
 731 
 732         .show_baseline = cyapa_gen6_show_baseline,
 733         .calibrate_store = cyapa_pip_do_calibrate,
 734 
 735         .initialize = cyapa_gen6_initialize,
 736 
 737         .state_parse = cyapa_pip_state_parse,
 738         .operational_check = cyapa_gen6_operational_check,
 739 
 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,
 744 
 745         .set_proximity = cyapa_gen6_set_proximity,
 746 };

/* [<][>][^][v][top][bottom][index][help] */