Skip to content

Commit 559b3df

Browse files
bentissdtor
authored andcommitted
Input: elan_i2c - add trackstick report
The Elan touchpads over I2C/SMBus also can handle a trackstick. Unfortunately, nothing tells us if the device supports trackstick (the information lies in the PS/2 node), so rely on device properties to determine whether to enable the trackstick node. Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939 Signed-off-by: Benjamin Tissoires <[email protected]> Acked-by: Rob Herring <[email protected]> Acked-by: KT Liao <[email protected]> Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent 89f84b8 commit 559b3df

File tree

2 files changed

+86
-3
lines changed

2 files changed

+86
-3
lines changed

Documentation/devicetree/bindings/input/elan_i2c.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Optional properties:
1414
- pinctrl-0: a phandle pointing to the pin settings for the device (see
1515
pinctrl binding [1]).
1616
- vcc-supply: a phandle for the regulator supplying 3.3V power.
17+
- elan,trackpoint: touchpad can support a trackpoint (boolean)
1718

1819
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
1920
[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt

drivers/input/mouse/elan_i2c_core.c

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <linux/jiffies.h>
3737
#include <linux/completion.h>
3838
#include <linux/of.h>
39+
#include <linux/property.h>
3940
#include <linux/regulator/consumer.h>
4041
#include <asm/unaligned.h>
4142

@@ -51,6 +52,7 @@
5152
#define ETP_MAX_FINGERS 5
5253
#define ETP_FINGER_DATA_LEN 5
5354
#define ETP_REPORT_ID 0x5D
55+
#define ETP_TP_REPORT_ID 0x5E
5456
#define ETP_REPORT_ID_OFFSET 2
5557
#define ETP_TOUCH_INFO_OFFSET 3
5658
#define ETP_FINGER_DATA_OFFSET 4
@@ -61,6 +63,7 @@
6163
struct elan_tp_data {
6264
struct i2c_client *client;
6365
struct input_dev *input;
66+
struct input_dev *tp_input; /* trackpoint input node */
6467
struct regulator *vcc;
6568

6669
const struct elan_transport_ops *ops;
@@ -930,6 +933,33 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
930933
input_sync(input);
931934
}
932935

936+
static void elan_report_trackpoint(struct elan_tp_data *data, u8 *report)
937+
{
938+
struct input_dev *input = data->tp_input;
939+
u8 *packet = &report[ETP_REPORT_ID_OFFSET + 1];
940+
int x, y;
941+
942+
if (!data->tp_input) {
943+
dev_warn_once(&data->client->dev,
944+
"received a trackpoint report while no trackpoint device has been created. Please report upstream.\n");
945+
return;
946+
}
947+
948+
input_report_key(input, BTN_LEFT, packet[0] & 0x01);
949+
input_report_key(input, BTN_RIGHT, packet[0] & 0x02);
950+
input_report_key(input, BTN_MIDDLE, packet[0] & 0x04);
951+
952+
if ((packet[3] & 0x0F) == 0x06) {
953+
x = packet[4] - (int)((packet[1] ^ 0x80) << 1);
954+
y = (int)((packet[2] ^ 0x80) << 1) - packet[5];
955+
956+
input_report_rel(input, REL_X, x);
957+
input_report_rel(input, REL_Y, y);
958+
}
959+
960+
input_sync(input);
961+
}
962+
933963
static irqreturn_t elan_isr(int irq, void *dev_id)
934964
{
935965
struct elan_tp_data *data = dev_id;
@@ -951,11 +981,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
951981
if (error)
952982
goto out;
953983

954-
if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID)
984+
switch (report[ETP_REPORT_ID_OFFSET]) {
985+
case ETP_REPORT_ID:
986+
elan_report_absolute(data, report);
987+
break;
988+
case ETP_TP_REPORT_ID:
989+
elan_report_trackpoint(data, report);
990+
break;
991+
default:
955992
dev_err(dev, "invalid report id data (%x)\n",
956993
report[ETP_REPORT_ID_OFFSET]);
957-
else
958-
elan_report_absolute(data, report);
994+
}
959995

960996
out:
961997
return IRQ_HANDLED;
@@ -966,6 +1002,36 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
9661002
* Elan initialization functions
9671003
******************************************************************
9681004
*/
1005+
1006+
static int elan_setup_trackpoint_input_device(struct elan_tp_data *data)
1007+
{
1008+
struct device *dev = &data->client->dev;
1009+
struct input_dev *input;
1010+
1011+
input = devm_input_allocate_device(dev);
1012+
if (!input)
1013+
return -ENOMEM;
1014+
1015+
input->name = "Elan TrackPoint";
1016+
input->id.bustype = BUS_I2C;
1017+
input->id.vendor = ELAN_VENDOR_ID;
1018+
input->id.product = data->product_id;
1019+
input_set_drvdata(input, data);
1020+
1021+
input_set_capability(input, EV_REL, REL_X);
1022+
input_set_capability(input, EV_REL, REL_Y);
1023+
input_set_capability(input, EV_KEY, BTN_LEFT);
1024+
input_set_capability(input, EV_KEY, BTN_RIGHT);
1025+
input_set_capability(input, EV_KEY, BTN_MIDDLE);
1026+
1027+
__set_bit(INPUT_PROP_POINTER, input->propbit);
1028+
__set_bit(INPUT_PROP_POINTING_STICK, input->propbit);
1029+
1030+
data->tp_input = input;
1031+
1032+
return 0;
1033+
}
1034+
9691035
static int elan_setup_input_device(struct elan_tp_data *data)
9701036
{
9711037
struct device *dev = &data->client->dev;
@@ -1140,6 +1206,12 @@ static int elan_probe(struct i2c_client *client,
11401206
if (error)
11411207
return error;
11421208

1209+
if (device_property_read_bool(&client->dev, "elan,trackpoint")) {
1210+
error = elan_setup_trackpoint_input_device(data);
1211+
if (error)
1212+
return error;
1213+
}
1214+
11431215
/*
11441216
* Platform code (ACPI, DTS) should normally set up interrupt
11451217
* for us, but in case it did not let's fall back to using falling
@@ -1177,6 +1249,16 @@ static int elan_probe(struct i2c_client *client,
11771249
return error;
11781250
}
11791251

1252+
if (data->tp_input) {
1253+
error = input_register_device(data->tp_input);
1254+
if (error) {
1255+
dev_err(&client->dev,
1256+
"failed to register TrackPoint input device: %d\n",
1257+
error);
1258+
return error;
1259+
}
1260+
}
1261+
11801262
/*
11811263
* Systems using device tree should set up wakeup via DTS,
11821264
* the rest will configure device as wakeup source by default.

0 commit comments

Comments
 (0)