* when in operational mode.
                 */
                error = cyapa->ops->set_power_mode(cyapa,
-                               PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
                if (error) {
                        dev_warn(dev, "set active power failed: %d\n", error);
                        goto out;
        pm_runtime_set_suspended(dev);
 
        if (cyapa->operational)
-               cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false);
+               cyapa->ops->set_power_mode(cyapa,
+                               PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
 
        mutex_unlock(&cyapa->state_sync_lock);
 }
                 */
                if (!input || cyapa->operational)
                        cyapa->ops->set_power_mode(cyapa,
-                               PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
                /* Gen3 always using polling mode for command. */
                if (cyapa->gen >= CYAPA_GEN5)
                        enable_irq(cyapa->client->irq);
                        disable_irq(cyapa->client->irq);
                if (!input || cyapa->operational)
                        cyapa->ops->set_power_mode(cyapa,
-                                                  PWR_MODE_OFF, 0, false);
+                                       PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
        }
 }
 
 
        /* Power down the device until we need it. */
        if (cyapa->operational)
-               cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false);
+               cyapa->ops->set_power_mode(cyapa,
+                               PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
 
        return 0;
 }
        /* Avoid command failures when TP was in OFF state. */
        if (cyapa->operational)
                cyapa->ops->set_power_mode(cyapa,
-                                          PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
 
        error = cyapa_detect(cyapa);
        if (error)
                /* Reset to power OFF state to save power when no user open. */
                if (cyapa->operational)
                        cyapa->ops->set_power_mode(cyapa,
-                                                  PWR_MODE_OFF, 0, false);
+                                       PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
        } else if (!error && cyapa->operational) {
                /*
                 * Make sure only enable runtime PM when device is
                power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode
                                                    : PWR_MODE_OFF;
                error = cyapa->ops->set_power_mode(cyapa, power_mode,
-                               cyapa->suspend_sleep_time, true);
+                               cyapa->suspend_sleep_time, CYAPA_PM_SUSPEND);
                if (error)
                        dev_err(dev, "suspend set power mode failed: %d\n",
                                        error);
        error = cyapa->ops->set_power_mode(cyapa,
                        cyapa->runtime_suspend_power_mode,
                        cyapa->runtime_suspend_sleep_time,
-                       false);
+                       CYAPA_PM_RUNTIME_SUSPEND);
        if (error)
                dev_warn(dev, "runtime suspend failed: %d\n", error);
 
        int error;
 
        error = cyapa->ops->set_power_mode(cyapa,
-                                          PWR_MODE_FULL_ACTIVE, 0, false);
+                       PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_RUNTIME_RESUME);
        if (error)
                dev_warn(dev, "runtime resume failed: %d\n", error);
 
 
 
 typedef bool (*cb_sort)(struct cyapa *, u8 *, int);
 
+enum cyapa_pm_stage {
+       CYAPA_PM_DEACTIVE,
+       CYAPA_PM_ACTIVE,
+       CYAPA_PM_SUSPEND,
+       CYAPA_PM_RESUME,
+       CYAPA_PM_RUNTIME_SUSPEND,
+       CYAPA_PM_RUNTIME_RESUME,
+};
+
 struct cyapa_dev_ops {
        int (*check_fw)(struct cyapa *, const struct firmware *);
        int (*bl_enter)(struct cyapa *);
        int (*sort_empty_output_data)(struct cyapa *,
                        u8 *, int *, cb_sort);
 
-       int (*set_power_mode)(struct cyapa *, u8, u16, bool);
+       int (*set_power_mode)(struct cyapa *, u8, u16, enum cyapa_pm_stage);
 
        int (*set_proximity)(struct cyapa *, bool);
 };
        u8 *resp_data;
        int *resp_len;
 
+       enum cyapa_pm_stage pm_stage;
+       struct mutex pm_stage_lock;
+
        u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE];
        u8 empty_buf[CYAPA_REG_MAP_SIZE];
 };
 
        { CYAPA_SMBUS_MIN_BASELINE, 1 },        /* CYAPA_CMD_MIN_BASELINE */
 };
 
+static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa);
 
 /*
  * cyapa_smbus_read_block - perform smbus block read command
  * Device power mode can only be set when device is in operational mode.
  */
 static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
-               u16 always_unused, bool is_suspend_unused)
+               u16 always_unused, enum cyapa_pm_stage pm_stage)
 {
-       int ret;
+       struct input_dev *input = cyapa->input;
        u8 power;
        int tries;
-       u16 sleep_time;
+       int sleep_time;
+       int interval;
+       int ret;
 
        if (cyapa->state != CYAPA_STATE_OP)
                return 0;
        if ((ret & PWR_MODE_MASK) == power_mode)
                return 0;
 
-       sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
+       sleep_time = (int)cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
        power = ret;
        power &= ~PWR_MODE_MASK;
        power |= power_mode & PWR_MODE_MASK;
         * doing so before issuing the next command may result in errors
         * depending on the command's content.
         */
-       msleep(sleep_time);
+       if (cyapa->operational && input && input->users &&
+           (pm_stage == CYAPA_PM_RUNTIME_SUSPEND ||
+            pm_stage == CYAPA_PM_RUNTIME_RESUME)) {
+               /* Try to polling in 120Hz, read may fail, just ignore it. */
+               interval = 1000 / 120;
+               while (sleep_time > 0) {
+                       if (sleep_time > interval)
+                               msleep(interval);
+                       else
+                               msleep(sleep_time);
+                       sleep_time -= interval;
+                       cyapa_gen3_try_poll_handler(cyapa);
+               }
+       } else {
+               msleep(sleep_time);
+       }
+
        return ret;
 }
 
                 * may cause problems, so we set the power mode first here.
                 */
                error = cyapa_gen3_set_power_mode(cyapa,
-                               PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
                if (error)
                        dev_err(dev, "%s: set full power mode failed: %d\n",
                                __func__, error);
        return false;
 }
 
-static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
+static int cyapa_gen3_event_process(struct cyapa *cyapa,
+                                   struct cyapa_reg_data *data)
 {
        struct input_dev *input = cyapa->input;
-       struct device *dev = &cyapa->client->dev;
-       struct cyapa_reg_data data;
        int num_fingers;
-       int ret;
        int i;
 
-       ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
-       if (ret != sizeof(data)) {
-               dev_err(dev, "failed to read report data, (%d)\n", ret);
-               return -EINVAL;
-       }
-
-       if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
-           (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
-           (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
-               dev_err(dev, "invalid device state bytes, %02x %02x\n",
-                       data.device_status, data.finger_btn);
-               return -EINVAL;
-       }
-
-       num_fingers = (data.finger_btn >> 4) & 0x0f;
+       num_fingers = (data->finger_btn >> 4) & 0x0f;
        for (i = 0; i < num_fingers; i++) {
-               const struct cyapa_touch *touch = &data.touches[i];
+               const struct cyapa_touch *touch = &data->touches[i];
                /* Note: touch->id range is 1 to 15; slots are 0 to 14. */
                int slot = touch->id - 1;
 
 
        if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
                input_report_key(input, BTN_LEFT,
-                                !!(data.finger_btn & OP_DATA_LEFT_BTN));
+                                !!(data->finger_btn & OP_DATA_LEFT_BTN));
        if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
                input_report_key(input, BTN_MIDDLE,
-                                !!(data.finger_btn & OP_DATA_MIDDLE_BTN));
+                                !!(data->finger_btn & OP_DATA_MIDDLE_BTN));
        if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
                input_report_key(input, BTN_RIGHT,
-                                !!(data.finger_btn & OP_DATA_RIGHT_BTN));
+                                !!(data->finger_btn & OP_DATA_RIGHT_BTN));
        input_sync(input);
 
        return 0;
 }
 
+static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
+{
+       struct device *dev = &cyapa->client->dev;
+       struct cyapa_reg_data data;
+       int ret;
+
+       ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
+       if (ret != sizeof(data)) {
+               dev_err(dev, "failed to read report data, (%d)\n", ret);
+               return -EINVAL;
+       }
+
+       if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
+           (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
+           (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
+               dev_err(dev, "invalid device state bytes: %02x %02x\n",
+                       data.device_status, data.finger_btn);
+               return -EINVAL;
+       }
+
+       return cyapa_gen3_event_process(cyapa, &data);
+}
+
+/*
+ * This function will be called in the cyapa_gen3_set_power_mode function,
+ * and it's known that it may failed in some situation after the set power
+ * mode command was sent. So this function is aimed to avoid the knwon
+ * and unwanted output I2C and data parse error messages.
+ */
+static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa)
+{
+       struct cyapa_reg_data data;
+       int ret;
+
+       ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
+       if (ret != sizeof(data))
+               return -EINVAL;
+
+       if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
+           (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
+           (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID)
+               return -EINVAL;
+
+       return cyapa_gen3_event_process(cyapa, &data);
+
+}
+
 static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; }
 static int cyapa_gen3_bl_initiate(struct cyapa *cyapa,
                const struct firmware *fw) { return 0; }
 
 static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
        0xff, 0xfe, 0xfd, 0x5a };
 
+static int cyapa_pip_event_process(struct cyapa *cyapa,
+                                  struct cyapa_pip_report_data *report_data);
+
 int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa)
 {
        struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
        atomic_set(&pip->cmd_issued, 0);
        mutex_init(&pip->cmd_lock);
 
+       mutex_init(&pip->pm_stage_lock);
+       pip->pm_stage = CYAPA_PM_DEACTIVE;
+
        pip->resp_sort_func = NULL;
        pip->in_progress_cmd = PIP_INVALID_CMD;
        pip->resp_data = NULL;
        return 0;
 }
 
+static void cyapa_set_pip_pm_state(struct cyapa *cyapa,
+                                  enum cyapa_pm_stage pm_stage)
+{
+       struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
+
+       mutex_lock(&pip->pm_stage_lock);
+       pip->pm_stage = pm_stage;
+       mutex_unlock(&pip->pm_stage_lock);
+}
+
+static void cyapa_reset_pip_pm_state(struct cyapa *cyapa)
+{
+       struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
+
+       /* Indicates the pip->pm_stage is not valid. */
+       mutex_lock(&pip->pm_stage_lock);
+       pip->pm_stage = CYAPA_PM_DEACTIVE;
+       mutex_unlock(&pip->pm_stage_lock);
+}
+
+static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa)
+{
+       struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
+       enum cyapa_pm_stage pm_stage;
+
+       mutex_lock(&pip->pm_stage_lock);
+       pm_stage = pip->pm_stage;
+       mutex_unlock(&pip->pm_stage_lock);
+
+       return pm_stage;
+}
+
 /**
  * This function is aimed to dump all not read data in Gen5 trackpad
  * before send any command, otherwise, the interrupt line will be blocked.
 int cyapa_empty_pip_output_data(struct cyapa *cyapa,
                u8 *buf, int *len, cb_sort func)
 {
+       struct input_dev *input = cyapa->input;
        struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
+       enum cyapa_pm_stage pm_stage = cyapa_get_pip_pm_state(cyapa);
        int length;
        int report_count;
        int empty_count;
                        *len = length;
                        /* Response found, success. */
                        return 0;
+               } else if (cyapa->operational && input && input->users &&
+                          (pm_stage == CYAPA_PM_RUNTIME_RESUME ||
+                           pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) {
+                       /* Parse the data and report it if it's valid. */
+                       cyapa_pip_event_process(cyapa,
+                              (struct cyapa_pip_report_data *)pip->empty_buf);
                }
 
                error = -EINVAL;
 }
 
 static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
-               u8 power_mode, u16 sleep_time, bool is_suspend)
+               u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
 {
        struct device *dev = &cyapa->client->dev;
        u8 power_state;
-       int error;
+       int error = 0;
 
        if (cyapa->state != CYAPA_STATE_GEN5_APP)
                return 0;
 
+       cyapa_set_pip_pm_state(cyapa, pm_stage);
+
        if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
                /*
                 * Assume TP in deep sleep mode when driver is loaded,
                        power_mode == PWR_MODE_BTN_ONLY ||
                        PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
                        /* Has in correct power mode state, early return. */
-                       return 0;
+                       goto out;
                }
        }
 
                error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
                if (error) {
                        dev_err(dev, "enter deep sleep fail: %d\n", error);
-                       return error;
+                       goto out;
                }
 
                PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
-               return 0;
+               goto out;
        }
 
        /*
                error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
                if (error) {
                        dev_err(dev, "deep sleep wake fail: %d\n", error);
-                       return error;
+                       goto out;
                }
        }
 
                                GEN5_POWER_STATE_ACTIVE);
                if (error) {
                        dev_err(dev, "change to active fail: %d\n", error);
-                       return error;
+                       goto out;
                }
 
                PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
                                GEN5_POWER_STATE_BTN_ONLY);
                if (error) {
                        dev_err(dev, "fail to button only mode: %d\n", error);
-                       return error;
+                       goto out;
                }
 
                PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
                if (error) {
                        dev_err(dev, "set power state to 0x%02x failed: %d\n",
                                power_state, error);
-                       return error;
+                       goto out;
                }
 
                /*
                 * is suspending which may cause interrupt line unable to be
                 * asserted again.
                 */
-               if (is_suspend)
+               if (pm_stage == CYAPA_PM_SUSPEND)
                        cyapa_gen5_disable_pip_report(cyapa);
 
                PIP_DEV_SET_PWR_STATE(cyapa,
                        cyapa_sleep_time_to_pwr_cmd(sleep_time));
        }
 
-       return 0;
+out:
+       cyapa_reset_pip_pm_state(cyapa);
+       return error;
 }
 
 int cyapa_pip_resume_scanning(struct cyapa *cyapa)
                 * the device state is required.
                 */
                error = cyapa_gen5_set_power_mode(cyapa,
-                               PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
                if (error)
                        dev_warn(dev, "%s: failed to set power active mode.\n",
                                __func__);
        struct device *dev = &cyapa->client->dev;
        struct cyapa_pip_report_data report_data;
        unsigned int report_len;
-       u8 report_id;
        int ret;
 
        if (!cyapa_is_pip_app_mode(cyapa)) {
                return -EINVAL;
        }
 
-       report_id = report_data.report_head[PIP_RESP_REPORT_ID_OFFSET];
+       return cyapa_pip_event_process(cyapa, &report_data);
+}
+
+static int cyapa_pip_event_process(struct cyapa *cyapa,
+                                  struct cyapa_pip_report_data *report_data)
+{
+       struct device *dev = &cyapa->client->dev;
+       unsigned int report_len;
+       u8 report_id;
+
+       report_len = get_unaligned_le16(
+                       &report_data->report_head[PIP_RESP_LENGTH_OFFSET]);
+       /* Idle, no data for report. */
+       if (report_len == PIP_RESP_LENGTH_SIZE)
+               return 0;
+
+       report_id = report_data->report_head[PIP_RESP_REPORT_ID_OFFSET];
        if (report_id == PIP_WAKEUP_EVENT_REPORT_ID &&
                        report_len == PIP_WAKEUP_EVENT_SIZE) {
                /*
        }
 
        if (report_id == PIP_TOUCH_REPORT_ID)
-               cyapa_pip_report_touches(cyapa, &report_data);
+               cyapa_pip_report_touches(cyapa, report_data);
        else if (report_id == PIP_PROXIMITY_REPORT_ID)
-               cyapa_pip_report_proximity(cyapa, &report_data);
+               cyapa_pip_report_proximity(cyapa, report_data);
        else
-               cyapa_pip_report_buttons(cyapa, &report_data);
+               cyapa_pip_report_buttons(cyapa, report_data);
 
        return 0;
 }
 
 }
 
 static int cyapa_gen6_set_power_mode(struct cyapa *cyapa,
-               u8 power_mode, u16 sleep_time, bool is_suspend)
+               u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
 {
        struct device *dev = &cyapa->client->dev;
        struct gen6_interval_setting *interval_setting =
                 * the device state is required.
                 */
                error = cyapa_gen6_set_power_mode(cyapa,
-                               PWR_MODE_FULL_ACTIVE, 0, false);
+                               PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
                if (error)
                        dev_warn(dev, "%s: failed to set power active mode.\n",
                                __func__);