if (cyapa->gen >= CYAPA_GEN5) {
input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);
+ input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
}
input_abs_set_res(input, ABS_MT_POSITION_X,
error);
}
+ /*
+ * Disable proximity interrupt when system idle, want true touch to
+ * wake the system.
+ */
+ if (cyapa->dev_pwr_mode != PWR_MODE_OFF)
+ cyapa->ops->set_proximity(cyapa, false);
+
if (device_may_wakeup(dev))
cyapa->irq_wake = (enable_irq_wake(client->irq) == 0);
cyapa->irq_wake = false;
}
- /* Update device states and runtime PM states. */
+ /*
+ * Update device states and runtime PM states.
+ * Re-Enable proximity interrupt after enter operational mode.
+ */
error = cyapa_reinitialize(cyapa);
if (error)
dev_warn(dev, "failed to reinitialize TP device: %d\n", error);
#define PIP_WAKEUP_EVENT_REPORT_ID 0x04
#define PIP_PUSH_BTN_REPORT_ID 0x06
#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */
+#define PIP_PROXIMITY_REPORT_ID 0x07
+
+#define PIP_PROXIMITY_REPORT_SIZE 6
+#define PIP_PROXIMITY_DISTANCE_OFFSET 0x05
+#define PIP_PROXIMITY_DISTANCE_MASK 0x01
#define PIP_TOUCH_REPORT_HEAD_SIZE 7
#define PIP_TOUCH_REPORT_MAX_SIZE 127
#define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00
#define PIP_SENSING_MODE_SELF_CAP 0x02
+#define PIP_SET_PROXIMITY 0x49
+
/* Macro of Gen5 */
#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100
#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe
return 0;
}
+int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable)
+{
+ u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, PIP_SET_PROXIMITY,
+ (u8)!!enable
+ };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_sort_tsg_pip_app_resp_data, false);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_SET_PROXIMITY) ||
+ !PIP_CMD_COMPLETE_SUCCESS(resp_data)) {
+ error = (error == -ETIMEDOUT) ? -EOPNOTSUPP : error;
+ return error < 0 ? error : -EINVAL;
+ }
+
+ return 0;
+}
+
int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state)
{
u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
dev_warn(dev, "%s: failed to set power active mode.\n",
__func__);
+ /* By default, the trackpad proximity function is enabled. */
+ error = cyapa_pip_set_proximity(cyapa, true);
+ if (error)
+ dev_warn(dev, "%s: failed to enable proximity.\n",
+ __func__);
+
/* Get trackpad product information. */
error = cyapa_gen5_get_query_data(cyapa);
if (error)
input_sync(input);
}
+static void cyapa_pip_report_proximity(struct cyapa *cyapa,
+ const struct cyapa_pip_report_data *report_data)
+{
+ struct input_dev *input = cyapa->input;
+ u8 distance = report_data->report_head[PIP_PROXIMITY_DISTANCE_OFFSET] &
+ PIP_PROXIMITY_DISTANCE_MASK;
+
+ input_report_abs(input, ABS_DISTANCE, distance);
+ input_sync(input);
+}
+
static void cyapa_pip_report_slot_data(struct cyapa *cyapa,
const struct cyapa_pip_touch_record *touch)
{
y = cyapa->max_abs_y - y;
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
+ input_report_abs(input, ABS_DISTANCE, 0);
input_report_abs(input, ABS_MT_PRESSURE,
touch->z);
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
} else if (report_id != PIP_TOUCH_REPORT_ID &&
report_id != PIP_BTN_REPORT_ID &&
report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
- report_id != PIP_PUSH_BTN_REPORT_ID) {
+ report_id != PIP_PUSH_BTN_REPORT_ID &&
+ report_id != PIP_PROXIMITY_REPORT_ID) {
/* Running in BL mode or unknown response data read. */
dev_err(dev, "invalid report_id=0x%02x\n", report_id);
return -EINVAL;
return 0;
}
+ if (report_id == PIP_PROXIMITY_REPORT_ID &&
+ report_len != PIP_PROXIMITY_REPORT_SIZE) {
+ /* Invalid report data length of proximity packet. */
+ dev_err(dev, "invalid proximity data, length=%d\n", report_len);
+ return 0;
+ }
+
if (report_id == PIP_TOUCH_REPORT_ID)
cyapa_pip_report_touches(cyapa, &report_data);
+ else if (report_id == PIP_PROXIMITY_REPORT_ID)
+ cyapa_pip_report_proximity(cyapa, &report_data);
else
cyapa_pip_report_buttons(cyapa, &report_data);
.irq_cmd_handler = cyapa_pip_irq_cmd_handler,
.sort_empty_output_data = cyapa_empty_pip_output_data,
.set_power_mode = cyapa_gen5_set_power_mode,
+
+ .set_proximity = cyapa_pip_set_proximity,
};
return 0;
}
+static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable)
+{
+ int error;
+
+ cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ);
+ error = cyapa_pip_set_proximity(cyapa, enable);
+ cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ);
+
+ return error;
+}
+
static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode)
{
u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode };
dev_warn(dev, "%s: failed to set power active mode.\n",
__func__);
+ /* By default, the trackpad proximity function is enabled. */
+ error = cyapa_pip_set_proximity(cyapa, true);
+ if (error)
+ dev_warn(dev, "%s: failed to enable proximity.\n",
+ __func__);
+
/* Get trackpad product information. */
error = cyapa_gen6_read_sys_info(cyapa);
if (error)
.irq_cmd_handler = cyapa_pip_irq_cmd_handler,
.sort_empty_output_data = cyapa_empty_pip_output_data,
.set_power_mode = cyapa_gen6_set_power_mode,
+
+ .set_proximity = cyapa_gen6_set_proximity,
};