Re: [PATCH v2 3/9] Input: elan_i2c - add trackstick report

2018-04-13 Thread Rob Herring
On Mon, Apr 09, 2018 at 11:10:45AM +0200, Benjamin Tissoires wrote:
> 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 a platform data to enable
> or not the trackstick node.
> 
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939
> 
> Signed-off-by: Benjamin Tissoires 
> 
> ---
> 
> changes in v2:
> - use of generic device property instead of platform data so
>   device tree can also make use of it
> ---
>  .../devicetree/bindings/input/elan_i2c.txt |  1 +

Acked-by: Rob Herring 

>  drivers/input/mouse/elan_i2c_core.c| 90 
> +-
>  2 files changed, 88 insertions(+), 3 deletions(-)


Re: [PATCH v2 3/9] Input: elan_i2c - add trackstick report

2018-04-13 Thread Rob Herring
On Mon, Apr 09, 2018 at 11:10:45AM +0200, Benjamin Tissoires wrote:
> 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 a platform data to enable
> or not the trackstick node.
> 
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939
> 
> Signed-off-by: Benjamin Tissoires 
> 
> ---
> 
> changes in v2:
> - use of generic device property instead of platform data so
>   device tree can also make use of it
> ---
>  .../devicetree/bindings/input/elan_i2c.txt |  1 +

Acked-by: Rob Herring 

>  drivers/input/mouse/elan_i2c_core.c| 90 
> +-
>  2 files changed, 88 insertions(+), 3 deletions(-)


[PATCH v2 3/9] Input: elan_i2c - add trackstick report

2018-04-09 Thread Benjamin Tissoires
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 a platform data to enable
or not the trackstick node.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939

Signed-off-by: Benjamin Tissoires 

---

changes in v2:
- use of generic device property instead of platform data so
  device tree can also make use of it
---
 .../devicetree/bindings/input/elan_i2c.txt |  1 +
 drivers/input/mouse/elan_i2c_core.c| 90 +-
 2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt 
b/Documentation/devicetree/bindings/input/elan_i2c.txt
index ee3242c4ba67..d80a83583238 100644
--- a/Documentation/devicetree/bindings/input/elan_i2c.txt
+++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
@@ -14,6 +14,7 @@ Optional properties:
 - pinctrl-0: a phandle pointing to the pin settings for the device (see
   pinctrl binding [1]).
 - vcc-supply: a phandle for the regulator supplying 3.3V power.
+- elan,trackpoint: touchpad can support a trackpoint (boolean)
 
 [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
diff --git a/drivers/input/mouse/elan_i2c_core.c 
b/drivers/input/mouse/elan_i2c_core.c
index 75e757520ef0..44e970931926 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -51,6 +52,7 @@
 #define ETP_MAX_FINGERS5
 #define ETP_FINGER_DATA_LEN5
 #define ETP_REPORT_ID  0x5D
+#define ETP_TP_REPORT_ID   0x5E
 #define ETP_REPORT_ID_OFFSET   2
 #define ETP_TOUCH_INFO_OFFSET  3
 #define ETP_FINGER_DATA_OFFSET 4
@@ -61,6 +63,7 @@
 struct elan_tp_data {
struct i2c_client   *client;
struct input_dev*input;
+   struct input_dev*tp_input; /* trackpoint input node */
struct regulator*vcc;
 
const struct elan_transport_ops *ops;
@@ -930,6 +933,34 @@ static void elan_report_absolute(struct elan_tp_data 
*data, u8 *packet)
input_sync(input);
 }
 
+static void elan_report_trackpoint(struct elan_tp_data *data, u8 *report)
+{
+   struct input_dev *input = data->tp_input;
+   u8 *packet = [ETP_REPORT_ID_OFFSET + 1];
+   int x, y;
+
+   if (!data->tp_input) {
+   dev_warn_once(>client->dev,
+ "received a trackpoint report while no trackpoint 
device has been created.\n"
+ "Please report upstream.\n");
+   return;
+   }
+
+   input_report_key(input, BTN_LEFT, packet[0] & 0x01);
+   input_report_key(input, BTN_RIGHT, packet[0] & 0x02);
+   input_report_key(input, BTN_MIDDLE, packet[0] & 0x04);
+
+   if ((packet[3] & 0x0F) == 0x06) {
+   x = packet[4] - (int)((packet[1]^0x80) << 1);
+   y = (int)((packet[2]^0x80) << 1) - packet[5];
+
+   input_report_rel(input, REL_X, x);
+   input_report_rel(input, REL_Y, y);
+   }
+
+   input_sync(input);
+}
+
 static irqreturn_t elan_isr(int irq, void *dev_id)
 {
struct elan_tp_data *data = dev_id;
@@ -951,11 +982,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
if (error)
goto out;
 
-   if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID)
+   switch (report[ETP_REPORT_ID_OFFSET]) {
+   case ETP_REPORT_ID:
+   elan_report_absolute(data, report);
+   break;
+   case ETP_TP_REPORT_ID:
+   elan_report_trackpoint(data, report);
+   break;
+   default:
dev_err(dev, "invalid report id data (%x)\n",
report[ETP_REPORT_ID_OFFSET]);
-   else
-   elan_report_absolute(data, report);
+   }
 
 out:
return IRQ_HANDLED;
@@ -966,6 +1003,37 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
  * Elan initialization functions
  **
  */
+
+static int elan_setup_trackpoint_input_device(struct elan_tp_data *data)
+{
+   struct device *dev = >client->dev;
+   struct input_dev *input;
+
+   input = devm_input_allocate_device(dev);
+   if (!input)
+   return -ENOMEM;
+
+   input->name = "Elan TrackPoint";
+   input->id.bustype = BUS_I2C;
+   input->id.vendor = ELAN_VENDOR_ID;
+   input->id.product = data->product_id;
+   input_set_drvdata(input, data);
+
+   input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+   input->relbit[BIT_WORD(REL_X)] =
+   BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+   input->keybit[BIT_WORD(BTN_LEFT)] =
+   BIT_MASK(BTN_LEFT) | 

[PATCH v2 3/9] Input: elan_i2c - add trackstick report

2018-04-09 Thread Benjamin Tissoires
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 a platform data to enable
or not the trackstick node.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=1313939

Signed-off-by: Benjamin Tissoires 

---

changes in v2:
- use of generic device property instead of platform data so
  device tree can also make use of it
---
 .../devicetree/bindings/input/elan_i2c.txt |  1 +
 drivers/input/mouse/elan_i2c_core.c| 90 +-
 2 files changed, 88 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt 
b/Documentation/devicetree/bindings/input/elan_i2c.txt
index ee3242c4ba67..d80a83583238 100644
--- a/Documentation/devicetree/bindings/input/elan_i2c.txt
+++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
@@ -14,6 +14,7 @@ Optional properties:
 - pinctrl-0: a phandle pointing to the pin settings for the device (see
   pinctrl binding [1]).
 - vcc-supply: a phandle for the regulator supplying 3.3V power.
+- elan,trackpoint: touchpad can support a trackpoint (boolean)
 
 [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
 [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
diff --git a/drivers/input/mouse/elan_i2c_core.c 
b/drivers/input/mouse/elan_i2c_core.c
index 75e757520ef0..44e970931926 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -51,6 +52,7 @@
 #define ETP_MAX_FINGERS5
 #define ETP_FINGER_DATA_LEN5
 #define ETP_REPORT_ID  0x5D
+#define ETP_TP_REPORT_ID   0x5E
 #define ETP_REPORT_ID_OFFSET   2
 #define ETP_TOUCH_INFO_OFFSET  3
 #define ETP_FINGER_DATA_OFFSET 4
@@ -61,6 +63,7 @@
 struct elan_tp_data {
struct i2c_client   *client;
struct input_dev*input;
+   struct input_dev*tp_input; /* trackpoint input node */
struct regulator*vcc;
 
const struct elan_transport_ops *ops;
@@ -930,6 +933,34 @@ static void elan_report_absolute(struct elan_tp_data 
*data, u8 *packet)
input_sync(input);
 }
 
+static void elan_report_trackpoint(struct elan_tp_data *data, u8 *report)
+{
+   struct input_dev *input = data->tp_input;
+   u8 *packet = [ETP_REPORT_ID_OFFSET + 1];
+   int x, y;
+
+   if (!data->tp_input) {
+   dev_warn_once(>client->dev,
+ "received a trackpoint report while no trackpoint 
device has been created.\n"
+ "Please report upstream.\n");
+   return;
+   }
+
+   input_report_key(input, BTN_LEFT, packet[0] & 0x01);
+   input_report_key(input, BTN_RIGHT, packet[0] & 0x02);
+   input_report_key(input, BTN_MIDDLE, packet[0] & 0x04);
+
+   if ((packet[3] & 0x0F) == 0x06) {
+   x = packet[4] - (int)((packet[1]^0x80) << 1);
+   y = (int)((packet[2]^0x80) << 1) - packet[5];
+
+   input_report_rel(input, REL_X, x);
+   input_report_rel(input, REL_Y, y);
+   }
+
+   input_sync(input);
+}
+
 static irqreturn_t elan_isr(int irq, void *dev_id)
 {
struct elan_tp_data *data = dev_id;
@@ -951,11 +982,17 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
if (error)
goto out;
 
-   if (report[ETP_REPORT_ID_OFFSET] != ETP_REPORT_ID)
+   switch (report[ETP_REPORT_ID_OFFSET]) {
+   case ETP_REPORT_ID:
+   elan_report_absolute(data, report);
+   break;
+   case ETP_TP_REPORT_ID:
+   elan_report_trackpoint(data, report);
+   break;
+   default:
dev_err(dev, "invalid report id data (%x)\n",
report[ETP_REPORT_ID_OFFSET]);
-   else
-   elan_report_absolute(data, report);
+   }
 
 out:
return IRQ_HANDLED;
@@ -966,6 +1003,37 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
  * Elan initialization functions
  **
  */
+
+static int elan_setup_trackpoint_input_device(struct elan_tp_data *data)
+{
+   struct device *dev = >client->dev;
+   struct input_dev *input;
+
+   input = devm_input_allocate_device(dev);
+   if (!input)
+   return -ENOMEM;
+
+   input->name = "Elan TrackPoint";
+   input->id.bustype = BUS_I2C;
+   input->id.vendor = ELAN_VENDOR_ID;
+   input->id.product = data->product_id;
+   input_set_drvdata(input, data);
+
+   input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+   input->relbit[BIT_WORD(REL_X)] =
+   BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+   input->keybit[BIT_WORD(BTN_LEFT)] =
+   BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+