diff options
author | Dudley Du <dudl@cypress.com> | 2015-07-20 16:57:53 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2015-07-23 17:34:05 -0700 |
commit | 945525ee607471630d07c309e036ae4a53abe37f (patch) | |
tree | 94d975a13c53bd6173d0f5dfdf4f5b555a9216df /drivers/input/mouse/cyapa_gen5.c | |
parent | c2c06c41f700b544c9331caf71c67edb5d131257 (diff) |
Input: cyapa - add proximity support for gen5 and gen6 modules
Gen5 and Gen6 trackpad devices are able to detect and report object
proximity data/events, add this function support in the cyapa driver
through the ABS_DISTANCE event.
Signed-off-by: Dudley Du <dudl@cypress.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/mouse/cyapa_gen5.c')
-rw-r--r-- | drivers/input/mouse/cyapa_gen5.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 4e19dce1dd62..fa135f855f34 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -52,6 +52,11 @@ #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 @@ -78,6 +83,8 @@ #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 @@ -1517,6 +1524,28 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) 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}; @@ -2491,6 +2520,12 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) 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) @@ -2607,6 +2642,17 @@ static void cyapa_pip_report_buttons(struct cyapa *cyapa, 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) { @@ -2628,6 +2674,7 @@ static void cyapa_pip_report_slot_data(struct cyapa *cyapa, 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, @@ -2715,7 +2762,8 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) } 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; @@ -2739,8 +2787,17 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) 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); @@ -2771,4 +2828,6 @@ const struct cyapa_dev_ops cyapa_gen5_ops = { .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, }; |