[PATCH v11 1/4] HID: wacom_sys: Add support for flipping the data values

Alistair Francis alistair at alistair23.me
Sat Oct 9 04:43:10 PDT 2021


Add support to the Wacom HID device for flipping the values based on
device tree settings. This allows us to support devices where the panel
is installed in a different orientation, such as the reMarkable2.

Signed-off-by: Alistair Francis <alistair at alistair23.me>
---
 .../bindings/input/hid-over-i2c.txt           | 20 ++++++
 drivers/hid/wacom_sys.c                       | 25 ++++++++
 drivers/hid/wacom_wac.c                       | 61 +++++++++++++++++++
 drivers/hid/wacom_wac.h                       | 13 ++++
 4 files changed, 119 insertions(+)

diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
index c76bafaf98d2..16ebd7c46049 100644
--- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
+++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
@@ -33,6 +33,26 @@ device-specific compatible properties, which should be used in addition to the
 - post-power-on-delay-ms: time required by the device after enabling its regulators
   or powering it on, before it is ready for communication.
 
+  flip-tilt-x:
+    type: boolean
+    description: Flip the tilt X values read from device
+
+  flip-tilt-y:
+    type: boolean
+    description: Flip the tilt Y values read from device
+
+  flip-pos-x:
+    type: boolean
+    description: Flip the X position values read from device
+
+  flip-pos-y:
+    type: boolean
+    description: Flip the Y position values read from device
+
+  flip-distance:
+    type: boolean
+    description: Flip the distance values read from device
+
 Example:
 
 	i2c-hid-dev at 2c {
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 93f49b766376..47d9590b10bd 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -10,6 +10,7 @@
 
 #include "wacom_wac.h"
 #include "wacom.h"
+#include <linux/of.h>
 #include <linux/input/mt.h>
 
 #define WAC_MSG_RETRIES		5
@@ -2730,6 +2731,28 @@ static void wacom_mode_change_work(struct work_struct *work)
 	return;
 }
 
+static void wacom_of_read(struct hid_device *hdev, struct wacom_wac *wacom_wac)
+{
+	if (IS_ENABLED(CONFIG_OF)) {
+		wacom_wac->flip_tilt_x = of_property_read_bool(hdev->dev.parent->of_node,
+							"flip-tilt-x");
+		wacom_wac->flip_tilt_y = of_property_read_bool(hdev->dev.parent->of_node,
+							"flip-tilt-y");
+		wacom_wac->flip_pos_x = of_property_read_bool(hdev->dev.parent->of_node,
+							"flip-pos-x");
+		wacom_wac->flip_pos_y = of_property_read_bool(hdev->dev.parent->of_node,
+							"flip-pos-y");
+		wacom_wac->flip_distance = of_property_read_bool(hdev->dev.parent->of_node,
+							"flip-distance");
+	} else {
+		wacom_wac->flip_tilt_x = false;
+		wacom_wac->flip_tilt_y = false;
+		wacom_wac->flip_pos_x = false;
+		wacom_wac->flip_pos_y = false;
+		wacom_wac->flip_distance = false;
+	}
+}
+
 static int wacom_probe(struct hid_device *hdev,
 		const struct hid_device_id *id)
 {
@@ -2797,6 +2820,8 @@ static int wacom_probe(struct hid_device *hdev,
 				 error);
 	}
 
+	wacom_of_read(hdev, wacom_wac);
+
 	wacom_wac->probe_complete = true;
 	return 0;
 }
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 33a6908995b1..c01f683e23fa 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -3261,6 +3261,63 @@ static int wacom_status_irq(struct wacom_wac *wacom_wac, size_t len)
 	return 0;
 }
 
+static int wacom_of_irq(struct wacom_wac *wacom_wac, size_t len)
+{
+	const struct wacom_features *features = &wacom_wac->features;
+	unsigned char *data = wacom_wac->data;
+	struct input_dev *input = wacom_wac->pen_input;
+	unsigned int x, y, pressure;
+	unsigned char tsw, f1, f2, ers;
+	short tilt_x, tilt_y, distance;
+
+	if (!IS_ENABLED(CONFIG_OF))
+		return 0;
+
+	tsw = data[1] & WACOM_TIP_SWITCH_bm;
+	ers = data[1] & WACOM_ERASER_bm;
+	f1 = data[1] & WACOM_BARREL_SWITCH_bm;
+	f2 = data[1] & WACOM_BARREL_SWITCH_2_bm;
+	x = le16_to_cpup((__le16 *)&data[2]);
+	y = le16_to_cpup((__le16 *)&data[4]);
+	pressure = le16_to_cpup((__le16 *)&data[6]);
+
+	/* Signed */
+	tilt_x = get_unaligned_le16(&data[9]);
+	tilt_y = get_unaligned_le16(&data[11]);
+
+	distance = get_unaligned_le16(&data[13]);
+
+	/* keep touch state for pen events */
+	if (!wacom_wac->shared->touch_down)
+		wacom_wac->tool[0] = (data[1] & 0x0c) ?
+			BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+	wacom_wac->shared->touch_down = data[1] & 0x20;
+
+	// Flip the values based on properties from the device tree
+
+	// Default to a negative value for distance as HID compliant Wacom
+	// devices generally specify the hovering distance as negative.
+	distance = wacom_wac->flip_distance ? distance : -distance;
+	x = wacom_wac->flip_pos_x ? (features->x_max - x) : x;
+	y = wacom_wac->flip_pos_y ? (features->y_max - y) : y;
+	tilt_x = wacom_wac->flip_tilt_x ? -tilt_x : tilt_x;
+	tilt_y = wacom_wac->flip_tilt_y ? -tilt_y : tilt_y;
+
+	input_report_key(input, BTN_TOUCH, tsw || ers);
+	input_report_key(input, wacom_wac->tool[0], wacom_wac->shared->touch_down);
+	input_report_key(input, BTN_STYLUS, f1);
+	input_report_key(input, BTN_STYLUS2, f2);
+	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);
+
+	return 1;
+}
+
 void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 {
 	bool sync;
@@ -3379,6 +3436,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 			sync = wacom_remote_irq(wacom_wac, len);
 		break;
 
+	case HID_GENERIC:
+		sync = wacom_of_irq(wacom_wac, len);
+		break;
+
 	default:
 		sync = false;
 		break;
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 8b2d4e5b2303..4dd5a56bf347 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -157,6 +157,14 @@
 #define WACOM_HID_WT_Y                  (WACOM_HID_UP_WACOMTOUCH | 0x131)
 #define WACOM_HID_WT_REPORT_VALID       (WACOM_HID_UP_WACOMTOUCH | 0x1d0)
 
+// 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)
+
 #define WACOM_BATTERY_USAGE(f)	(((f)->hid == HID_DG_BATTERYSTRENGTH) || \
 				 ((f)->hid == WACOM_HID_WD_BATTERY_CHARGING) || \
 				 ((f)->hid == WACOM_HID_WD_BATTERY_LEVEL))
@@ -357,6 +365,11 @@ struct wacom_wac {
 	bool has_mode_change;
 	bool is_direct_mode;
 	bool is_invalid_bt_frame;
+	bool flip_tilt_x;
+	bool flip_tilt_y;
+	bool flip_pos_x;
+	bool flip_pos_y;
+	bool flip_distance;
 };
 
 #endif
-- 
2.31.1




More information about the linux-arm-kernel mailing list