Skip to content

Commit 04d5ce6

Browse files
jinglewudtor
authored andcommitted
Input: elan_i2c - add support for high resolution reports
Newer controllers (identified as "pattern" version 2) send higher resolution reports, with 16-bit X and Y coordinates (previous generations used 12-bit values). These new high resolution reports use report ID of 0x60. SMbus controllers use the same buffer size for both the new and old reports, and because of that high resolution reports no longer carry area of contact data with SMbus. Signed-off-by: Jingle Wu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 3d712af commit 04d5ce6

File tree

4 files changed

+126
-59
lines changed

4 files changed

+126
-59
lines changed

drivers/input/mouse/elan_i2c.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#define ETP_CALIBRATE_MAX_LEN 3
2828

29+
#define ETP_FEATURE_REPORT_MK BIT(0)
30+
2931
/* IAP Firmware handling */
3032
#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
3133
#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
@@ -82,7 +84,11 @@ struct elan_transport_ops {
8284
int (*finish_fw_update)(struct i2c_client *client,
8385
struct completion *reset_done);
8486

85-
int (*get_report)(struct i2c_client *client, u8 *report);
87+
int (*get_report_features)(struct i2c_client *client, u8 pattern,
88+
unsigned int *features,
89+
unsigned int *report_len);
90+
int (*get_report)(struct i2c_client *client, u8 *report,
91+
unsigned int report_len);
8692
int (*get_pressure_adjustment)(struct i2c_client *client,
8793
int *adjustment);
8894
int (*get_pattern)(struct i2c_client *client, u8 *pattern);

drivers/input/mouse/elan_i2c_core.c

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@
5050
#define ETP_MAX_FINGERS 5
5151
#define ETP_FINGER_DATA_LEN 5
5252
#define ETP_REPORT_ID 0x5D
53+
#define ETP_REPORT_ID2 0x60 /* High precision report */
5354
#define ETP_TP_REPORT_ID 0x5E
5455
#define ETP_REPORT_ID_OFFSET 2
5556
#define ETP_TOUCH_INFO_OFFSET 3
5657
#define ETP_FINGER_DATA_OFFSET 4
5758
#define ETP_HOVER_INFO_OFFSET 30
58-
#define ETP_MAX_REPORT_LEN 34
59+
#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */
60+
#define ETP_MAX_REPORT_LEN 39
5961

6062
/* The main device structure */
6163
struct elan_tp_data {
@@ -85,6 +87,8 @@ struct elan_tp_data {
8587
u8 sm_version;
8688
u8 iap_version;
8789
u16 fw_checksum;
90+
unsigned int report_features;
91+
unsigned int report_len;
8892
int pressure_adjustment;
8993
u8 mode;
9094
u16 ic_type;
@@ -359,6 +363,12 @@ static int elan_query_device_info(struct elan_tp_data *data)
359363
if (error)
360364
return error;
361365

366+
error = data->ops->get_report_features(data->client, data->pattern,
367+
&data->report_features,
368+
&data->report_len);
369+
if (error)
370+
return error;
371+
362372
error = elan_get_fwinfo(data->ic_type, data->iap_version,
363373
&data->fw_validpage_count,
364374
&data->fw_signature_address,
@@ -371,16 +381,21 @@ static int elan_query_device_info(struct elan_tp_data *data)
371381
return 0;
372382
}
373383

374-
static unsigned int elan_convert_resolution(u8 val)
384+
static unsigned int elan_convert_resolution(u8 val, u8 pattern)
375385
{
376386
/*
377-
* (value from firmware) * 10 + 790 = dpi
378-
*
387+
* pattern <= 0x01:
388+
* (value from firmware) * 10 + 790 = dpi
389+
* else
390+
* ((value from firmware) + 3) * 100 = dpi
391+
*/
392+
int res = pattern <= 0x01 ?
393+
(int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100;
394+
/*
379395
* We also have to convert dpi to dots/mm (*10/254 to avoid floating
380396
* point).
381397
*/
382-
383-
return ((int)(char)val * 10 + 790) * 10 / 254;
398+
return res * 10 / 254;
384399
}
385400

386401
static int elan_query_device_parameters(struct elan_tp_data *data)
@@ -429,8 +444,8 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
429444
if (error)
430445
return error;
431446

432-
data->x_res = elan_convert_resolution(hw_x_res);
433-
data->y_res = elan_convert_resolution(hw_y_res);
447+
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
448+
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
434449
} else {
435450
data->x_res = (data->max_x + 1) / x_mm;
436451
data->y_res = (data->max_y + 1) / y_mm;
@@ -908,24 +923,22 @@ static const struct attribute_group *elan_sysfs_groups[] = {
908923
* Elan isr functions
909924
******************************************************************
910925
*/
911-
static void elan_report_contact(struct elan_tp_data *data,
912-
int contact_num, bool contact_valid,
913-
u8 *finger_data)
926+
static void elan_report_contact(struct elan_tp_data *data, int contact_num,
927+
bool contact_valid, bool high_precision,
928+
u8 *packet, u8 *finger_data)
914929
{
915930
struct input_dev *input = data->input;
916931
unsigned int pos_x, pos_y;
917-
unsigned int pressure, mk_x, mk_y;
918-
unsigned int area_x, area_y, major, minor;
919-
unsigned int scaled_pressure;
932+
unsigned int pressure, scaled_pressure;
920933

921934
if (contact_valid) {
922-
pos_x = ((finger_data[0] & 0xf0) << 4) |
923-
finger_data[1];
924-
pos_y = ((finger_data[0] & 0x0f) << 8) |
925-
finger_data[2];
926-
mk_x = (finger_data[3] & 0x0f);
927-
mk_y = (finger_data[3] >> 4);
928-
pressure = finger_data[4];
935+
if (high_precision) {
936+
pos_x = get_unaligned_be16(&finger_data[0]);
937+
pos_y = get_unaligned_be16(&finger_data[2]);
938+
} else {
939+
pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1];
940+
pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2];
941+
}
929942

930943
if (pos_x > data->max_x || pos_y > data->max_y) {
931944
dev_dbg(input->dev.parent,
@@ -935,18 +948,8 @@ static void elan_report_contact(struct elan_tp_data *data,
935948
return;
936949
}
937950

938-
/*
939-
* To avoid treating large finger as palm, let's reduce the
940-
* width x and y per trace.
941-
*/
942-
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
943-
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
944-
945-
major = max(area_x, area_y);
946-
minor = min(area_x, area_y);
947-
951+
pressure = finger_data[4];
948952
scaled_pressure = pressure + data->pressure_adjustment;
949-
950953
if (scaled_pressure > ETP_MAX_PRESSURE)
951954
scaled_pressure = ETP_MAX_PRESSURE;
952955

@@ -955,16 +958,37 @@ static void elan_report_contact(struct elan_tp_data *data,
955958
input_report_abs(input, ABS_MT_POSITION_X, pos_x);
956959
input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
957960
input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
958-
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
959-
input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
960-
input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
961+
962+
if (data->report_features & ETP_FEATURE_REPORT_MK) {
963+
unsigned int mk_x, mk_y, area_x, area_y;
964+
u8 mk_data = high_precision ?
965+
packet[ETP_MK_DATA_OFFSET + contact_num] :
966+
finger_data[3];
967+
968+
mk_x = mk_data & 0x0f;
969+
mk_y = mk_data >> 4;
970+
971+
/*
972+
* To avoid treating large finger as palm, let's reduce
973+
* the width x and y per trace.
974+
*/
975+
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
976+
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
977+
978+
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
979+
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
980+
max(area_x, area_y));
981+
input_report_abs(input, ABS_MT_TOUCH_MINOR,
982+
min(area_x, area_y));
983+
}
961984
} else {
962985
input_mt_slot(input, contact_num);
963986
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
964987
}
965988
}
966989

967-
static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
990+
static void elan_report_absolute(struct elan_tp_data *data, u8 *packet,
991+
bool high_precision)
968992
{
969993
struct input_dev *input = data->input;
970994
u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET];
@@ -973,11 +997,12 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
973997
u8 hover_info = packet[ETP_HOVER_INFO_OFFSET];
974998
bool contact_valid, hover_event;
975999

976-
hover_event = hover_info & 0x40;
977-
for (i = 0; i < ETP_MAX_FINGERS; i++) {
978-
contact_valid = tp_info & (1U << (3 + i));
979-
elan_report_contact(data, i, contact_valid, finger_data);
1000+
hover_event = hover_info & BIT(6);
9801001

1002+
for (i = 0; i < ETP_MAX_FINGERS; i++) {
1003+
contact_valid = tp_info & BIT(3 + i);
1004+
elan_report_contact(data, i, contact_valid, high_precision,
1005+
packet, finger_data);
9811006
if (contact_valid)
9821007
finger_data += ETP_FINGER_DATA_LEN;
9831008
}
@@ -1034,15 +1059,18 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
10341059
goto out;
10351060
}
10361061

1037-
error = data->ops->get_report(data->client, report);
1062+
error = data->ops->get_report(data->client, report, data->report_len);
10381063
if (error)
10391064
goto out;
10401065

10411066
pm_wakeup_event(dev, 0);
10421067

10431068
switch (report[ETP_REPORT_ID_OFFSET]) {
10441069
case ETP_REPORT_ID:
1045-
elan_report_absolute(data, report);
1070+
elan_report_absolute(data, report, false);
1071+
break;
1072+
case ETP_REPORT_ID2:
1073+
elan_report_absolute(data, report, true);
10461074
break;
10471075
case ETP_TP_REPORT_ID:
10481076
elan_report_trackpoint(data, report);
@@ -1133,7 +1161,9 @@ static int elan_setup_input_device(struct elan_tp_data *data)
11331161
input_abs_set_res(input, ABS_X, data->x_res);
11341162
input_abs_set_res(input, ABS_Y, data->y_res);
11351163
input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
1136-
input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
1164+
if (data->report_features & ETP_FEATURE_REPORT_MK)
1165+
input_set_abs_params(input, ABS_TOOL_WIDTH,
1166+
0, ETP_FINGER_WIDTH, 0, 0);
11371167
input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
11381168

11391169
/* And MT parameters */
@@ -1143,10 +1173,12 @@ static int elan_setup_input_device(struct elan_tp_data *data)
11431173
input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res);
11441174
input_set_abs_params(input, ABS_MT_PRESSURE, 0,
11451175
ETP_MAX_PRESSURE, 0, 0);
1146-
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
1147-
ETP_FINGER_WIDTH * max_width, 0, 0);
1148-
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
1149-
ETP_FINGER_WIDTH * min_width, 0, 0);
1176+
if (data->report_features & ETP_FEATURE_REPORT_MK) {
1177+
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
1178+
0, ETP_FINGER_WIDTH * max_width, 0, 0);
1179+
input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
1180+
0, ETP_FINGER_WIDTH * min_width, 0, 0);
1181+
}
11501182

11511183
data->input = input;
11521184

drivers/input/mouse/elan_i2c_i2c.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
#define ETP_I2C_IAP_TYPE_CMD 0x0304
6161

6262
#define ETP_I2C_REPORT_LEN 34
63+
#define ETP_I2C_REPORT_LEN_ID2 39
64+
#define ETP_I2C_REPORT_MAX_LEN 39
6365
#define ETP_I2C_DESC_LENGTH 30
6466
#define ETP_I2C_REPORT_DESC_LENGTH 158
6567
#define ETP_I2C_INF_LENGTH 2
@@ -394,15 +396,15 @@ static int elan_i2c_get_max(struct i2c_client *client,
394396
return error;
395397
}
396398

397-
*max_x = le16_to_cpup((__le16 *)val) & 0x0fff;
399+
*max_x = le16_to_cpup((__le16 *)val);
398400

399401
error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val);
400402
if (error) {
401403
dev_err(&client->dev, "failed to get Y dimension: %d\n", error);
402404
return error;
403405
}
404406

405-
*max_y = le16_to_cpup((__le16 *)val) & 0x0fff;
407+
*max_y = le16_to_cpup((__le16 *)val);
406408

407409
return 0;
408410
}
@@ -674,12 +676,12 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client,
674676
struct completion *completion)
675677
{
676678
struct device *dev = &client->dev;
677-
int error;
679+
int error = 0;
678680
int len;
679-
u8 buffer[ETP_I2C_REPORT_LEN];
681+
u8 buffer[ETP_I2C_REPORT_MAX_LEN];
680682

681-
len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
682-
if (len != ETP_I2C_REPORT_LEN) {
683+
len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN);
684+
if (len <= 0) {
683685
error = len < 0 ? len : -EIO;
684686
dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
685687
error, len);
@@ -713,20 +715,31 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client,
713715
return 0;
714716
}
715717

716-
static int elan_i2c_get_report(struct i2c_client *client, u8 *report)
718+
static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern,
719+
unsigned int *features,
720+
unsigned int *report_len)
721+
{
722+
*features = ETP_FEATURE_REPORT_MK;
723+
*report_len = pattern <= 0x01 ?
724+
ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2;
725+
return 0;
726+
}
727+
728+
static int elan_i2c_get_report(struct i2c_client *client,
729+
u8 *report, unsigned int report_len)
717730
{
718731
int len;
719732

720-
len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN);
733+
len = i2c_master_recv(client, report, report_len);
721734
if (len < 0) {
722735
dev_err(&client->dev, "failed to read report data: %d\n", len);
723736
return len;
724737
}
725738

726-
if (len != ETP_I2C_REPORT_LEN) {
739+
if (len != report_len) {
727740
dev_err(&client->dev,
728741
"wrong report length (%d vs %d expected)\n",
729-
len, ETP_I2C_REPORT_LEN);
742+
len, report_len);
730743
return -EIO;
731744
}
732745

@@ -763,5 +776,6 @@ const struct elan_transport_ops elan_i2c_ops = {
763776

764777
.get_pattern = elan_i2c_get_pattern,
765778

779+
.get_report_features = elan_i2c_get_report_features,
766780
.get_report = elan_i2c_get_report,
767781
};

drivers/input/mouse/elan_i2c_smbus.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,21 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size
469469
return 0;
470470
}
471471

472-
static int elan_smbus_get_report(struct i2c_client *client, u8 *report)
472+
static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern,
473+
unsigned int *features,
474+
unsigned int *report_len)
475+
{
476+
/*
477+
* SMBus controllers with pattern 2 lack area info, as newer
478+
* high-precision packets use that space for coordinates.
479+
*/
480+
*features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0;
481+
*report_len = ETP_SMBUS_REPORT_LEN;
482+
return 0;
483+
}
484+
485+
static int elan_smbus_get_report(struct i2c_client *client,
486+
u8 *report, unsigned int report_len)
473487
{
474488
int len;
475489

@@ -534,6 +548,7 @@ const struct elan_transport_ops elan_smbus_ops = {
534548
.write_fw_block = elan_smbus_write_fw_block,
535549
.finish_fw_update = elan_smbus_finish_fw_update,
536550

551+
.get_report_features = elan_smbus_get_report_features,
537552
.get_report = elan_smbus_get_report,
538553
.get_pattern = elan_smbus_get_pattern,
539554
};

0 commit comments

Comments
 (0)