2021-08-19 11:21:38

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 00/11] Add Wacom I2C support to rM2

Add support to the reMarkable2 (rM2) for the Wacom I2C device.

This is based on the reMarkable Linux fork and with this series I am
able to use the Wacom digitiser on the rM2.

v9:
- Add two new patches
- Fixup the device tree interrupt line
v7:
- Fx the compatible name and documentation

Alistair Francis (11):
dt-bindings: Add Wacom to vendor bindings
dt-bindings: touchscreen: Initial commit of wacom,i2c
Input: wacom_i2c - Add device tree support to wacom_i2c
Input: wacom_i2c - Add touchscren properties
Input: wacom_i2c - Add support for distance and tilt x/y
Input: wacom_i2c - Clean up the query device fields
Input: wacom_i2c - Add support for vdd regulator
Input: wacom_i2c - Use macros for the bit masks
Input: wacom_i2c - Allow flipping the values from the DT
ARM: imx_v6_v7_defconfig: Enable Wacom I2C
ARM: dts: imx7d: remarkable2: add wacom digitizer device

.../input/touchscreen/wacom,generic.yaml | 66 ++++++
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
arch/arm/boot/dts/imx7d-remarkable2.dts | 61 ++++++
arch/arm/configs/imx_v6_v7_defconfig | 1 +
drivers/input/touchscreen/wacom_i2c.c | 203 ++++++++++++++----
5 files changed, 297 insertions(+), 36 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml

--
2.31.1


2021-08-19 11:21:43

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 01/11] dt-bindings: Add Wacom to vendor bindings

Signed-off-by: Alistair Francis <[email protected]>
Acked-by: Rob Herring <[email protected]>
Cc: [email protected]
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 4dfaae537daf..31745c45dd92 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1252,6 +1252,8 @@ patternProperties:
description: Vision Optical Technology Co., Ltd.
"^vxt,.*":
description: VXT Ltd
+ "^wacom,.*":
+ description: Wacom Co., Ltd
"^wand,.*":
description: Wandbord (Technexion)
"^waveshare,.*":
--
2.31.1

2021-08-19 11:21:50

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 02/11] dt-bindings: touchscreen: Initial commit of wacom,i2c

Signed-off-by: Alistair Francis <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Cc: [email protected]
---
.../input/touchscreen/wacom,generic.yaml | 48 +++++++++++++++++++
1 file changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml

diff --git a/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
new file mode 100644
index 000000000000..a8a7f362b0ce
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/touchscreen/wacom,generic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Wacom I2C Controller
+
+maintainers:
+ - Alistair Francis <[email protected]>
+
+allOf:
+ - $ref: touchscreen.yaml#
+
+properties:
+ compatible:
+ const: wacom,i2c-30
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply:
+ description: Power Supply
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include "dt-bindings/interrupt-controller/irq.h"
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ digitiser@9 {
+ compatible = "wacom,i2c-30";
+ reg = <0x9>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+ vdd-supply = <&reg_touch>;
+ };
+ };
--
2.31.1

2021-08-19 11:22:04

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 03/11] Input: wacom_i2c - Add device tree support to wacom_i2c

Allow the wacom-i2c device to be exposed via device tree.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 22826c387da5..6053595f2b30 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <asm/unaligned.h>

#define WACOM_CMD_QUERY0 0x04
@@ -241,10 +242,17 @@ static const struct i2c_device_id wacom_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);

+static const struct of_device_id wacom_i2c_of_match_table[] = {
+ { .compatible = "wacom,i2c-30" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wacom_i2c_of_match_table);
+
static struct i2c_driver wacom_i2c_driver = {
.driver = {
.name = "wacom_i2c",
.pm = &wacom_i2c_pm,
+ .of_match_table = wacom_i2c_of_match_table,
},

.probe = wacom_i2c_probe,
--
2.31.1

2021-08-19 11:22:08

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 04/11] Input: wacom_i2c - Add touchscren properties

Connect touchscreen properties to the wacom_i2c.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 6053595f2b30..28255c77d426 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/irq.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <asm/unaligned.h>
@@ -33,6 +34,8 @@ struct wacom_features {
struct wacom_i2c {
struct i2c_client *client;
struct input_dev *input;
+ struct touchscreen_properties props;
+ struct wacom_features features;
u8 data[WACOM_QUERY_SIZE];
bool prox;
int tool;
@@ -90,6 +93,7 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
{
struct wacom_i2c *wac_i2c = dev_id;
struct input_dev *input = wac_i2c->input;
+ struct wacom_features *features = &wac_i2c->features;
u8 *data = wac_i2c->data;
unsigned int x, y, pressure;
unsigned char tsw, f1, f2, ers;
@@ -114,6 +118,8 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)

wac_i2c->prox = data[3] & 0x20;

+ touchscreen_report_pos(input, &wac_i2c->props, features->x_max,
+ features->y_max, true);
input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, wac_i2c->tool, wac_i2c->prox);
input_report_key(input, BTN_STYLUS, f1);
@@ -151,7 +157,7 @@ static int wacom_i2c_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct wacom_i2c *wac_i2c;
struct input_dev *input;
- struct wacom_features features = { 0 };
+ struct wacom_features *features;
int error;

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
@@ -159,14 +165,15 @@ static int wacom_i2c_probe(struct i2c_client *client,
return -EIO;
}

- error = wacom_query_device(client, &features);
- if (error)
- return error;
-
wac_i2c = devm_kzalloc(dev, sizeof(*wac_i2c), GFP_KERNEL);
if (!wac_i2c)
return -ENOMEM;

+ features = &wac_i2c->features;
+ error = wacom_query_device(client, features);
+ if (error)
+ return error;
+
wac_i2c->client = client;

input = devm_input_allocate_device(dev);
@@ -178,7 +185,7 @@ static int wacom_i2c_probe(struct i2c_client *client,
input->name = "Wacom I2C Digitizer";
input->id.bustype = BUS_I2C;
input->id.vendor = 0x56a;
- input->id.version = features.fw_version;
+ input->id.version = features->fw_version;
input->open = wacom_i2c_open;
input->close = wacom_i2c_close;

@@ -190,10 +197,11 @@ static int wacom_i2c_probe(struct i2c_client *client,
__set_bit(BTN_STYLUS2, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);

- input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
- input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
+ touchscreen_parse_properties(input, true, &wac_i2c->props);
+ input_set_abs_params(input, ABS_X, 0, features->x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, features->y_max, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
- 0, features.pressure_max, 0, 0);
+ 0, features->pressure_max, 0, 0);

input_set_drvdata(input, wac_i2c);

--
2.31.1

2021-08-19 11:22:16

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 05/11] Input: wacom_i2c - Add support for distance and tilt x/y

Add support for the distance and tilt x/y.

This is based on the out of tree rM2 driver.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 35 +++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 28255c77d426..4d0c19fbada4 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -22,12 +22,18 @@
#define WACOM_CMD_QUERY3 0x02
#define WACOM_CMD_THROW0 0x05
#define WACOM_CMD_THROW1 0x00
-#define WACOM_QUERY_SIZE 19
+#define WACOM_QUERY_SIZE 22
+
+#define WACOM_DISTANCE_TILT_VERSION 0x30

struct wacom_features {
int x_max;
int y_max;
int pressure_max;
+ int distance_max;
+ int distance_physical_max;
+ int tilt_x_max;
+ int tilt_y_max;
char fw_version;
};

@@ -80,6 +86,17 @@ static int wacom_query_device(struct i2c_client *client,
features->y_max = get_unaligned_le16(&data[5]);
features->pressure_max = get_unaligned_le16(&data[11]);
features->fw_version = get_unaligned_le16(&data[13]);
+ if (features->fw_version >= WACOM_DISTANCE_TILT_VERSION) {
+ features->distance_max = data[15];
+ features->distance_physical_max = data[16];
+ features->tilt_x_max = get_unaligned_le16(&data[17]);
+ features->tilt_y_max = get_unaligned_le16(&data[19]);
+ } else {
+ features->distance_max = -1;
+ features->distance_physical_max = -1;
+ features->tilt_x_max = -1;
+ features->tilt_y_max = -1;
+ }

dev_dbg(&client->dev,
"x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
@@ -97,6 +114,7 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
u8 *data = wac_i2c->data;
unsigned int x, y, pressure;
unsigned char tsw, f1, f2, ers;
+ short tilt_x, tilt_y, distance;
int error;

error = i2c_master_recv(wac_i2c->client,
@@ -112,6 +130,12 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);

+ /* Signed */
+ tilt_x = le16_to_cpup((__le16 *)&data[11]);
+ tilt_y = le16_to_cpup((__le16 *)&data[13]);
+
+ distance = le16_to_cpup((__le16 *)&data[15]);
+
if (!wac_i2c->prox)
wac_i2c->tool = (data[3] & 0x0c) ?
BTN_TOOL_RUBBER : BTN_TOOL_PEN;
@@ -127,6 +151,9 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
+ input_report_abs(input, ABS_DISTANCE, distance);
+ input_report_abs(input, ABS_TILT_X, tilt_x);
+ input_report_abs(input, ABS_TILT_Y, tilt_y);
input_sync(input);

out:
@@ -202,7 +229,11 @@ static int wacom_i2c_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_Y, 0, features->y_max, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
0, features->pressure_max, 0, 0);
-
+ input_set_abs_params(input, ABS_DISTANCE, 0, features->distance_max, 0, 0);
+ input_set_abs_params(input, ABS_TILT_X, -features->tilt_x_max,
+ features->tilt_x_max, 0, 0);
+ input_set_abs_params(input, ABS_TILT_Y, -features->tilt_y_max,
+ features->tilt_y_max, 0, 0);
input_set_drvdata(input, wac_i2c);

error = devm_request_threaded_irq(dev, client->irq, NULL, wacom_i2c_irq,
--
2.31.1

2021-08-19 11:22:31

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 07/11] Input: wacom_i2c - Add support for vdd regulator

Add support for a VDD regulator. This allows the kernel to probe the
Wacom-I2C device on the rM2.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 33a3ba110171..fd486b8ef2cc 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -13,6 +13,7 @@
#include <linux/irq.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/of.h>
#include <asm/unaligned.h>
@@ -59,6 +60,7 @@ struct wacom_i2c {
struct input_dev *input;
struct touchscreen_properties props;
struct wacom_features features;
+ struct regulator *vdd;
u8 data[WACOM_QUERY_SIZE];
bool prox;
int tool;
@@ -220,6 +222,16 @@ static int wacom_i2c_probe(struct i2c_client *client,
if (!wac_i2c)
return -ENOMEM;

+ wac_i2c->vdd = regulator_get(&client->dev, "vdd");
+ if (IS_ERR(wac_i2c->vdd))
+ return PTR_ERR(wac_i2c->vdd);
+
+ error = regulator_enable(wac_i2c->vdd);
+ if (error) {
+ regulator_put(wac_i2c->vdd);
+ return error;
+ }
+
features = &wac_i2c->features;
error = wacom_query_device(client, features);
if (error)
@@ -228,8 +240,11 @@ static int wacom_i2c_probe(struct i2c_client *client,
wac_i2c->client = client;

input = devm_input_allocate_device(dev);
- if (!input)
+ if (!input) {
+ regulator_disable(wac_i2c->vdd);
+ regulator_put(wac_i2c->vdd);
return -ENOMEM;
+ }

wac_i2c->input = input;

@@ -264,6 +279,8 @@ static int wacom_i2c_probe(struct i2c_client *client,
IRQF_ONESHOT, "wacom_i2c", wac_i2c);
if (error) {
dev_err(dev, "Failed to request IRQ: %d\n", error);
+ regulator_disable(wac_i2c->vdd);
+ regulator_put(wac_i2c->vdd);
return error;
}

@@ -273,6 +290,8 @@ static int wacom_i2c_probe(struct i2c_client *client,
error = input_register_device(wac_i2c->input);
if (error) {
dev_err(dev, "Failed to register input device: %d\n", error);
+ regulator_disable(wac_i2c->vdd);
+ regulator_put(wac_i2c->vdd);
return error;
}

--
2.31.1

2021-08-19 11:22:44

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 09/11] Input: wacom_i2c - Allow flipping the values from the DT

Allow the device tree properties to flip the tilx, position or distance
values.

This is required for the stylus to work correctly on the reMarkable 2.

Signed-off-by: Alistair Francis <[email protected]>
---
.../input/touchscreen/wacom,generic.yaml | 18 ++++++++++
drivers/input/touchscreen/wacom_i2c.c | 33 +++++++++++++++++++
2 files changed, 51 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
index a8a7f362b0ce..0da63fd92ea1 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
@@ -25,6 +25,24 @@ properties:
vdd-supply:
description: Power Supply

+ flip-tilt-x:
+ type: boolean
+
+ flip-tilt-y:
+ type: boolean
+
+ flip-pos-x:
+ type: boolean
+
+ flip-pos-y:
+ type: boolean
+
+ flip-distance:
+ type: boolean
+
+ flip-pressure:
+ type: boolean
+
required:
- compatible
- reg
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index c6579a1a8d04..82b62a768451 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -72,6 +72,13 @@ struct wacom_i2c {
u8 data[WACOM_QUERY_SIZE];
bool prox;
int tool;
+
+ bool flip_tilt_x;
+ bool flip_tilt_y;
+ bool flip_pos_x;
+ bool flip_pos_y;
+ bool flip_distance;
+ bool flip_pressure;
};

static int wacom_query_device(struct i2c_client *client,
@@ -140,6 +147,20 @@ static int wacom_query_device(struct i2c_client *client,
return 0;
}

+#ifdef CONFIG_OF
+static void wacom_of_read(struct wacom_i2c *wac_i2c)
+{
+ struct i2c_client *client = wac_i2c->client;
+
+ wac_i2c->flip_tilt_x = of_property_read_bool(client->dev.of_node, "flip-tilt-x");
+ wac_i2c->flip_tilt_y = of_property_read_bool(client->dev.of_node, "flip-tilt-y");
+ wac_i2c->flip_pos_x = of_property_read_bool(client->dev.of_node, "flip-pos-x");
+ wac_i2c->flip_pos_y = of_property_read_bool(client->dev.of_node, "flip-pos-y");
+ wac_i2c->flip_distance = of_property_read_bool(client->dev.of_node, "flip-distance");
+ wac_i2c->flip_pressure = of_property_read_bool(client->dev.of_node, "flip-pressure");
+}
+#endif
+
static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
{
struct wacom_i2c *wac_i2c = dev_id;
@@ -176,6 +197,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)

wac_i2c->prox = data[3] & 0x20;

+ // Flip the values based on properties from the device tree
+ pressure = wac_i2c->flip_pressure ? (features->pressure_max - pressure) : pressure;
+ distance = wac_i2c->flip_distance ? -distance : distance;
+ x = wac_i2c->flip_pos_x ? (features->x_max - x) : x;
+ y = wac_i2c->flip_pos_y ? (features->y_max - y) : y;
+ tilt_x = wac_i2c->flip_tilt_x ? -tilt_x : tilt_x;
+ tilt_y = wac_i2c->flip_tilt_y ? -tilt_y : tilt_y;
+
touchscreen_report_pos(input, &wac_i2c->props, features->x_max,
features->y_max, true);
input_report_key(input, BTN_TOUCH, tsw || ers);
@@ -303,6 +332,10 @@ static int wacom_i2c_probe(struct i2c_client *client,
return error;
}

+#ifdef CONFIG_OF
+ wacom_of_read(wac_i2c);
+#endif
+
return 0;
}

--
2.31.1

2021-08-19 11:22:50

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 11/11] ARM: dts: imx7d: remarkable2: add wacom digitizer device

Enable the wacom_i2c touchscreen for the reMarkable2.

Signed-off-by: Alistair Francis <[email protected]>
---
arch/arm/boot/dts/imx7d-remarkable2.dts | 61 +++++++++++++++++++++++++
1 file changed, 61 insertions(+)

diff --git a/arch/arm/boot/dts/imx7d-remarkable2.dts b/arch/arm/boot/dts/imx7d-remarkable2.dts
index 89cbf13097a4..052f9da32398 100644
--- a/arch/arm/boot/dts/imx7d-remarkable2.dts
+++ b/arch/arm/boot/dts/imx7d-remarkable2.dts
@@ -34,6 +34,19 @@ reg_brcm: regulator-brcm {
startup-delay-us = <150>;
};

+ reg_digitizer: regulator-digitizer {
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_3V3_DIGITIZER";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_digitizer_reg>;
+ pinctrl-1 = <&pinctrl_digitizer_reg>;
+ gpio = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ startup-delay-us = <100000>; /* 100 ms */
+ };
+
wifi_pwrseq: wifi_pwrseq {
compatible = "mmc-pwrseq-simple";
pinctrl-names = "default";
@@ -51,6 +64,28 @@ &clks {
assigned-clock-rates = <0>, <32768>;
};

+&i2c1 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ wacom_digitizer: digitizer@9 {
+ compatible = "wacom,i2c-30";
+ reg = <0x09>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wacom>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
+ flip-tilt-x;
+ flip-tilt-y;
+ flip-pos-x;
+ flip-pos-y;
+ flip-distance;
+ vdd-supply = <&reg_digitizer>;
+ };
+};
+
&snvs_pwrkey {
status = "okay";
};
@@ -117,6 +152,25 @@ &wdog1 {
fsl,ext-reset-output;
};

+&iomuxc_lpsr {
+ pinctrl_digitizer_reg: digitizerreggrp {
+ fsl,pins = <
+ /* DIGITIZER_PWR_EN */
+ MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6 0x14
+ >;
+ };
+
+ pinctrl_wacom: wacomgrp {
+ fsl,pins = <
+ /*MX7D_PAD_LPSR_GPIO1_IO05__GPIO1_IO5 0x00000014 /* FWE */
+ MX7D_PAD_LPSR_GPIO1_IO04__GPIO1_IO4 0x00000074 /* PDCTB */
+ MX7D_PAD_LPSR_GPIO1_IO01__GPIO1_IO1 0x00000034 /* WACOM INT */
+ /*MX7D_PAD_LPSR_GPIO1_IO06__GPIO1_IO6 0x00000014 /* WACOM PWR ENABLE */
+ /*MX7D_PAD_LPSR_GPIO1_IO00__GPIO1_IO0 0x00000074 /* WACOM RESET */
+ >;
+ };
+};
+
&iomuxc {
pinctrl_brcm_reg: brcmreggrp {
fsl,pins = <
@@ -125,6 +179,13 @@ MX7D_PAD_SAI1_TX_BCLK__GPIO6_IO13 0x14
>;
};

+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f
+ MX7D_PAD_I2C1_SCL__I2C1_SCL 0x4000007f
+ >;
+ };
+
pinctrl_uart1: uart1grp {
fsl,pins = <
MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79
--
2.31.1

2021-08-19 11:23:46

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 06/11] Input: wacom_i2c - Clean up the query device fields

Improve the query device fields to be more verbose.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 64 ++++++++++++++++++---------
1 file changed, 44 insertions(+), 20 deletions(-)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 4d0c19fbada4..33a3ba110171 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -13,15 +13,32 @@
#include <linux/irq.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
+#include <linux/reset.h>
#include <linux/of.h>
#include <asm/unaligned.h>

-#define WACOM_CMD_QUERY0 0x04
-#define WACOM_CMD_QUERY1 0x00
-#define WACOM_CMD_QUERY2 0x33
-#define WACOM_CMD_QUERY3 0x02
-#define WACOM_CMD_THROW0 0x05
-#define WACOM_CMD_THROW1 0x00
+// Registers
+#define WACOM_COMMAND_LSB 0x04
+#define WACOM_COMMAND_MSB 0x00
+
+#define WACOM_DATA_LSB 0x05
+#define WACOM_DATA_MSB 0x00
+
+// Report types
+#define REPORT_FEATURE 0x30
+
+// Requests / operations
+#define OPCODE_GET_REPORT 0x02
+
+// Power settings
+#define POWER_ON 0x00
+#define POWER_SLEEP 0x01
+
+// Input report ids
+#define WACOM_PEN_DATA_REPORT 2
+#define WACOM_SHINONOME_REPORT 26
+
+#define WACOM_QUERY_REPORT 3
#define WACOM_QUERY_SIZE 22

#define WACOM_DISTANCE_TILT_VERSION 0x30
@@ -51,27 +68,30 @@ static int wacom_query_device(struct i2c_client *client,
struct wacom_features *features)
{
int ret;
- u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1,
- WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 };
- u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 };
u8 data[WACOM_QUERY_SIZE];
+
+ u8 get_query_data_cmd[] = {
+ WACOM_COMMAND_LSB,
+ WACOM_COMMAND_MSB,
+ REPORT_FEATURE | WACOM_QUERY_REPORT,
+ OPCODE_GET_REPORT,
+ WACOM_DATA_LSB,
+ WACOM_DATA_MSB,
+ };
+
struct i2c_msg msgs[] = {
+ // Request reading of feature ReportID: 3 (Pen Query Data)
{
.addr = client->addr,
.flags = 0,
- .len = sizeof(cmd1),
- .buf = cmd1,
- },
- {
- .addr = client->addr,
- .flags = 0,
- .len = sizeof(cmd2),
- .buf = cmd2,
+ .len = sizeof(get_query_data_cmd),
+ .buf = get_query_data_cmd,
},
+ // Read 21 bytes
{
.addr = client->addr,
.flags = I2C_M_RD,
- .len = sizeof(data),
+ .len = WACOM_QUERY_SIZE - 1,
.buf = data,
},
};
@@ -99,9 +119,13 @@ static int wacom_query_device(struct i2c_client *client,
}

dev_dbg(&client->dev,
- "x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
+ "x_max:%d, y_max:%d, pressure:%d, fw:%d, "
+ "distance: %d, phys distance: %d, "
+ "tilt_x_max: %d, tilt_y_max: %d\n",
features->x_max, features->y_max,
- features->pressure_max, features->fw_version);
+ features->pressure_max, features->fw_version,
+ features->distance_max, features->distance_physical_max,
+ features->tilt_x_max, features->tilt_y_max);

return 0;
}
--
2.31.1

2021-08-19 11:23:49

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 10/11] ARM: imx_v6_v7_defconfig: Enable Wacom I2C

Enable the Wacom I2C in the imx defconfig as it is used by the
reMarkable2 tablet.

Signed-off-by: Alistair Francis <[email protected]>
---
arch/arm/configs/imx_v6_v7_defconfig | 1 +
1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 079fcd8d1d11..477dac1edc75 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -176,6 +176,7 @@ CONFIG_TOUCHSCREEN_DA9052=y
CONFIG_TOUCHSCREEN_EGALAX=y
CONFIG_TOUCHSCREEN_GOODIX=y
CONFIG_TOUCHSCREEN_ILI210X=y
+CONFIG_TOUCHSCREEN_WACOM_I2C=y
CONFIG_TOUCHSCREEN_MAX11801=y
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
CONFIG_TOUCHSCREEN_EDT_FT5X06=y
--
2.31.1

2021-08-19 11:24:00

by Alistair Francis

[permalink] [raw]
Subject: [PATCH v9 08/11] Input: wacom_i2c - Use macros for the bit masks

To make the code easier to read use macros for the bit masks.

Signed-off-by: Alistair Francis <[email protected]>
---
drivers/input/touchscreen/wacom_i2c.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index fd486b8ef2cc..c6579a1a8d04 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -18,6 +18,14 @@
#include <linux/of.h>
#include <asm/unaligned.h>

+// Bitmasks (for data[3])
+#define WACOM_TIP_SWITCH_bm (1 << 0)
+#define WACOM_BARREL_SWITCH_bm (1 << 1)
+#define WACOM_ERASER_bm (1 << 2)
+#define WACOM_INVERT_bm (1 << 3)
+#define WACOM_BARREL_SWITCH_2_bm (1 << 4)
+#define WACOM_IN_RANGE_bm (1 << 5)
+
// Registers
#define WACOM_COMMAND_LSB 0x04
#define WACOM_COMMAND_MSB 0x00
@@ -148,10 +156,10 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
if (error < 0)
goto out;

- tsw = data[3] & 0x01;
- ers = data[3] & 0x04;
- f1 = data[3] & 0x02;
- f2 = data[3] & 0x10;
+ tsw = data[3] & WACOM_TIP_SWITCH_bm;
+ ers = data[3] & WACOM_ERASER_bm;
+ f1 = data[3] & WACOM_BARREL_SWITCH_bm;
+ f2 = data[3] & WACOM_BARREL_SWITCH_2_bm;
x = le16_to_cpup((__le16 *)&data[4]);
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
--
2.31.1

2021-08-23 07:08:45

by Ahmad Fatoum

[permalink] [raw]
Subject: Re: [PATCH v9 05/11] Input: wacom_i2c - Add support for distance and tilt x/y

On 18.08.21 17:49, Alistair Francis wrote:
> Add support for the distance and tilt x/y.
>
> This is based on the out of tree rM2 driver.
>
> Signed-off-by: Alistair Francis <[email protected]>
> ---
> drivers/input/touchscreen/wacom_i2c.c | 35 +++++++++++++++++++++++++--
> 1 file changed, 33 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
> index 28255c77d426..4d0c19fbada4 100644
> --- a/drivers/input/touchscreen/wacom_i2c.c
> +++ b/drivers/input/touchscreen/wacom_i2c.c

> + /* Signed */
> + tilt_x = le16_to_cpup((__le16 *)&data[11]);
> + tilt_y = le16_to_cpup((__le16 *)&data[13]);
> +
> + distance = le16_to_cpup((__le16 *)&data[15]);

Use get_unaligned_u16 for all three. The existing code doesn't need to do this,
because with the current struct layout, the array is suitable aligned
for 2 byte accesses. You are accessing data at odd indices though, so you
need to use an unaligned accessor.

Cheers,
Ahmad

> +
> if (!wac_i2c->prox)
> wac_i2c->tool = (data[3] & 0x0c) ?
> BTN_TOOL_RUBBER : BTN_TOOL_PEN;
> @@ -127,6 +151,9 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
> input_report_abs(input, ABS_X, x);
> input_report_abs(input, ABS_Y, y);
> input_report_abs(input, ABS_PRESSURE, pressure);
> + input_report_abs(input, ABS_DISTANCE, distance);
> + input_report_abs(input, ABS_TILT_X, tilt_x);
> + input_report_abs(input, ABS_TILT_Y, tilt_y);
> input_sync(input);
>
> out:
> @@ -202,7 +229,11 @@ static int wacom_i2c_probe(struct i2c_client *client,
> input_set_abs_params(input, ABS_Y, 0, features->y_max, 0, 0);
> input_set_abs_params(input, ABS_PRESSURE,
> 0, features->pressure_max, 0, 0);
> -
> + input_set_abs_params(input, ABS_DISTANCE, 0, features->distance_max, 0, 0);
> + input_set_abs_params(input, ABS_TILT_X, -features->tilt_x_max,
> + features->tilt_x_max, 0, 0);
> + input_set_abs_params(input, ABS_TILT_Y, -features->tilt_y_max,
> + features->tilt_y_max, 0, 0);
> input_set_drvdata(input, wac_i2c);
>
> error = devm_request_threaded_irq(dev, client->irq, NULL, wacom_i2c_irq,
>


--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |

2021-08-23 18:17:31

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v9 09/11] Input: wacom_i2c - Allow flipping the values from the DT

On Thu, Aug 19, 2021 at 01:49:33AM +1000, Alistair Francis wrote:
> Allow the device tree properties to flip the tilx, position or distance
> values.
>
> This is required for the stylus to work correctly on the reMarkable 2.
>
> Signed-off-by: Alistair Francis <[email protected]>
> ---
> .../input/touchscreen/wacom,generic.yaml | 18 ++++++++++
> drivers/input/touchscreen/wacom_i2c.c | 33 +++++++++++++++++++
> 2 files changed, 51 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
> index a8a7f362b0ce..0da63fd92ea1 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
> +++ b/Documentation/devicetree/bindings/input/touchscreen/wacom,generic.yaml
> @@ -25,6 +25,24 @@ properties:
> vdd-supply:
> description: Power Supply
>
> + flip-tilt-x:
> + type: boolean

These all need descriptions.

> +
> + flip-tilt-y:
> + type: boolean
> +
> + flip-pos-x:
> + type: boolean
> +
> + flip-pos-y:
> + type: boolean
> +
> + flip-distance:
> + type: boolean
> +
> + flip-pressure:
> + type: boolean

I don't understand how you flip pressure?

> +
> required:
> - compatible
> - reg
> diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
> index c6579a1a8d04..82b62a768451 100644
> --- a/drivers/input/touchscreen/wacom_i2c.c
> +++ b/drivers/input/touchscreen/wacom_i2c.c
> @@ -72,6 +72,13 @@ struct wacom_i2c {
> u8 data[WACOM_QUERY_SIZE];
> bool prox;
> int tool;
> +
> + bool flip_tilt_x;
> + bool flip_tilt_y;
> + bool flip_pos_x;
> + bool flip_pos_y;
> + bool flip_distance;
> + bool flip_pressure;
> };
>
> static int wacom_query_device(struct i2c_client *client,
> @@ -140,6 +147,20 @@ static int wacom_query_device(struct i2c_client *client,
> return 0;
> }
>
> +#ifdef CONFIG_OF


Use 'if (!IS_ENABLED(CONFIG_OF))' in the function and drop all the
ifdefs.

> +static void wacom_of_read(struct wacom_i2c *wac_i2c)
> +{
> + struct i2c_client *client = wac_i2c->client;
> +
> + wac_i2c->flip_tilt_x = of_property_read_bool(client->dev.of_node, "flip-tilt-x");
> + wac_i2c->flip_tilt_y = of_property_read_bool(client->dev.of_node, "flip-tilt-y");
> + wac_i2c->flip_pos_x = of_property_read_bool(client->dev.of_node, "flip-pos-x");
> + wac_i2c->flip_pos_y = of_property_read_bool(client->dev.of_node, "flip-pos-y");
> + wac_i2c->flip_distance = of_property_read_bool(client->dev.of_node, "flip-distance");
> + wac_i2c->flip_pressure = of_property_read_bool(client->dev.of_node, "flip-pressure");
> +}
> +#endif
> +
> static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
> {
> struct wacom_i2c *wac_i2c = dev_id;
> @@ -176,6 +197,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
>
> wac_i2c->prox = data[3] & 0x20;
>
> + // Flip the values based on properties from the device tree
> + pressure = wac_i2c->flip_pressure ? (features->pressure_max - pressure) : pressure;
> + distance = wac_i2c->flip_distance ? -distance : distance;
> + x = wac_i2c->flip_pos_x ? (features->x_max - x) : x;
> + y = wac_i2c->flip_pos_y ? (features->y_max - y) : y;
> + tilt_x = wac_i2c->flip_tilt_x ? -tilt_x : tilt_x;
> + tilt_y = wac_i2c->flip_tilt_y ? -tilt_y : tilt_y;
> +
> touchscreen_report_pos(input, &wac_i2c->props, features->x_max,
> features->y_max, true);
> input_report_key(input, BTN_TOUCH, tsw || ers);
> @@ -303,6 +332,10 @@ static int wacom_i2c_probe(struct i2c_client *client,
> return error;
> }
>
> +#ifdef CONFIG_OF
> + wacom_of_read(wac_i2c);
> +#endif
> +
> return 0;
> }
>
> --
> 2.31.1
>
>