linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] Input: of_touchscreen - support device-properties with other prefixes
@ 2025-02-20 13:09 Dmitry Mastykin
  2025-02-20 13:09 ` [PATCH 2/2] Input: himax_hx83112b - add pen support Dmitry Mastykin
  0 siblings, 1 reply; 2+ messages in thread
From: Dmitry Mastykin @ 2025-02-20 13:09 UTC (permalink / raw)
  To: job, dmitry.torokhov, linux-input, linux-kernel, felix; +Cc: Dmitry Mastykin

Introduce touchscreen_parse_properties_prefix() function, that can parse
device-properties with given prefix. E.g. both touchscreen-swapped-x-y
and pen-swapped-x-y may be parsed.
Some touchscreens may have different pen axis orientation,
and that should be set in the device tree. Separate set of
device-properties with prefix "pen-" or "stylus-" will be used to set
pen resolution and axis orientation.

Signed-off-by: Dmitry Mastykin <mastichi@gmail.com>
---
 drivers/input/touchscreen.c       | 83 +++++++++++++++++++------------
 include/linux/input/touchscreen.h |  3 ++
 2 files changed, 54 insertions(+), 32 deletions(-)

diff --git a/drivers/input/touchscreen.c b/drivers/input/touchscreen.c
index 4620e20d0190..0ed6b85b1ded 100644
--- a/drivers/input/touchscreen.c
+++ b/drivers/input/touchscreen.c
@@ -64,12 +64,35 @@ static void touchscreen_set_params(struct input_dev *dev,
  */
 void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 				  struct touchscreen_properties *prop)
+{
+	touchscreen_parse_properties_prefix(input, multitouch, prop, "touchscreen");
+}
+EXPORT_SYMBOL(touchscreen_parse_properties);
+
+static char *prefix_prop(const char *property, const char *prefix, char *buf, size_t len)
+{
+	ssize_t n, ret;
+
+	n = strscpy(buf, prefix, len);
+	if (n > 0) {
+		ret = strscpy(buf + n, "-", len - n);
+		if (ret > 0) {
+			n += ret;
+			strscpy(buf + n, property, len - n);
+		}
+	}
+	return buf;
+}
+
+void touchscreen_parse_properties_prefix(struct input_dev *input, bool multitouch,
+					 struct touchscreen_properties *prop, const char *prefix)
 {
 	struct device *dev = input->dev.parent;
 	struct input_absinfo *absinfo;
 	unsigned int axis, axis_x, axis_y;
 	unsigned int minimum, maximum, fuzz;
 	bool data_present;
+	char buf[64];
 
 	input_alloc_absinfo(input);
 	if (!input->absinfo)
@@ -78,41 +101,37 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 	axis_x = multitouch ? ABS_MT_POSITION_X : ABS_X;
 	axis_y = multitouch ? ABS_MT_POSITION_Y : ABS_Y;
 
-	data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-x",
-						input_abs_get_min(input, axis_x),
-						&minimum);
-	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-x",
-						 input_abs_get_max(input,
-								   axis_x) + 1,
-						 &maximum);
-	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x",
-						 input_abs_get_fuzz(input, axis_x),
-						 &fuzz);
+	data_present =
+	    touchscreen_get_prop_u32(dev, prefix_prop("min-x", prefix, buf, sizeof(buf)),
+				     input_abs_get_min(input, axis_x), &minimum);
+	data_present |=
+	    touchscreen_get_prop_u32(dev, prefix_prop("size-x", prefix, buf, sizeof(buf)),
+				     input_abs_get_max(input, axis_x) + 1, &maximum);
+	data_present |=
+	    touchscreen_get_prop_u32(dev, prefix_prop("fuzz-x", prefix, buf, sizeof(buf)),
+				     input_abs_get_fuzz(input, axis_x), &fuzz);
 	if (data_present)
 		touchscreen_set_params(input, axis_x, minimum, maximum - 1, fuzz);
 
-	data_present = touchscreen_get_prop_u32(dev, "touchscreen-min-y",
-						input_abs_get_min(input, axis_y),
-						&minimum);
-	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-size-y",
-						 input_abs_get_max(input,
-								   axis_y) + 1,
-						 &maximum);
-	data_present |= touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y",
-						 input_abs_get_fuzz(input, axis_y),
-						 &fuzz);
+	data_present =
+	    touchscreen_get_prop_u32(dev, prefix_prop("min-y", prefix, buf, sizeof(buf)),
+				     input_abs_get_min(input, axis_y), &minimum);
+	data_present |=
+	    touchscreen_get_prop_u32(dev, prefix_prop("size-y", prefix, buf, sizeof(buf)),
+				     input_abs_get_max(input, axis_y) + 1, &maximum);
+	data_present |=
+	    touchscreen_get_prop_u32(dev, prefix_prop("fuzz-y", prefix, buf, sizeof(buf)),
+				     input_abs_get_fuzz(input, axis_y), &fuzz);
 	if (data_present)
 		touchscreen_set_params(input, axis_y, minimum, maximum - 1, fuzz);
 
 	axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE;
-	data_present = touchscreen_get_prop_u32(dev,
-						"touchscreen-max-pressure",
-						input_abs_get_max(input, axis),
-						&maximum);
-	data_present |= touchscreen_get_prop_u32(dev,
-						 "touchscreen-fuzz-pressure",
-						 input_abs_get_fuzz(input, axis),
-						 &fuzz);
+	data_present =
+	    touchscreen_get_prop_u32(dev, prefix_prop("max-pressure", prefix, buf, sizeof(buf)),
+				     input_abs_get_max(input, axis), &maximum);
+	data_present |=
+	    touchscreen_get_prop_u32(dev, prefix_prop("fuzz-pressure", prefix, buf, sizeof(buf)),
+				     input_abs_get_fuzz(input, axis), &fuzz);
 	if (data_present)
 		touchscreen_set_params(input, axis, 0, maximum, fuzz);
 
@@ -123,7 +142,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 	prop->max_y = input_abs_get_max(input, axis_y);
 
 	prop->invert_x =
-		device_property_read_bool(dev, "touchscreen-inverted-x");
+	    device_property_read_bool(dev, prefix_prop("inverted-x", prefix, buf, sizeof(buf)));
 	if (prop->invert_x) {
 		absinfo = &input->absinfo[axis_x];
 		absinfo->maximum -= absinfo->minimum;
@@ -131,7 +150,7 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 	}
 
 	prop->invert_y =
-		device_property_read_bool(dev, "touchscreen-inverted-y");
+	    device_property_read_bool(dev, prefix_prop("inverted-y", prefix, buf, sizeof(buf)));
 	if (prop->invert_y) {
 		absinfo = &input->absinfo[axis_y];
 		absinfo->maximum -= absinfo->minimum;
@@ -139,11 +158,11 @@ void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 	}
 
 	prop->swap_x_y =
-		device_property_read_bool(dev, "touchscreen-swapped-x-y");
+	    device_property_read_bool(dev, prefix_prop("swapped-x-y", prefix, buf, sizeof(buf)));
 	if (prop->swap_x_y)
 		swap(input->absinfo[axis_x], input->absinfo[axis_y]);
 }
-EXPORT_SYMBOL(touchscreen_parse_properties);
+EXPORT_SYMBOL(touchscreen_parse_properties_prefix);
 
 static void
 touchscreen_apply_prop_to_x_y(const struct touchscreen_properties *prop,
diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h
index fe66e2b58f62..42aed1ccc2cd 100644
--- a/include/linux/input/touchscreen.h
+++ b/include/linux/input/touchscreen.h
@@ -20,6 +20,9 @@ struct touchscreen_properties {
 void touchscreen_parse_properties(struct input_dev *input, bool multitouch,
 				  struct touchscreen_properties *prop);
 
+void touchscreen_parse_properties_prefix(struct input_dev *input, bool multitouch,
+					 struct touchscreen_properties *prop, const char *prefix);
+
 void touchscreen_set_mt_pos(struct input_mt_pos *pos,
 			    const struct touchscreen_properties *prop,
 			    unsigned int x, unsigned int y);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH 2/2] Input: himax_hx83112b - add pen support
  2025-02-20 13:09 [PATCH 1/2] Input: of_touchscreen - support device-properties with other prefixes Dmitry Mastykin
@ 2025-02-20 13:09 ` Dmitry Mastykin
  0 siblings, 0 replies; 2+ messages in thread
From: Dmitry Mastykin @ 2025-02-20 13:09 UTC (permalink / raw)
  To: job, dmitry.torokhov, linux-input, linux-kernel, felix; +Cc: Dmitry Mastykin

Add pen support based on Himax Android driver, that provides two versions
of pen data structure. Pen support is activated in device-tree by
"pen-present" property. Its value is the version number. We tested with:
	pen-present = <1>;
Additional set of device-properties must be used to set pen resolution
and axis orientation:
	pen-size-x = <2000>;
	pen-size-y = <1200>;
	...
Touchscreen size device-properties may be added for pen points/mm
calculation:
	touchscreen-x-mm = <239>;
	touchscreen-y-mm = <143>;

Tested on: Starry Electronic XR109IA2T LCM (HX83102J)

Signed-off-by: Dmitry Mastykin <mastichi@gmail.com>
---
 drivers/input/touchscreen/himax_hx83112b.c | 135 ++++++++++++++++++++-
 1 file changed, 131 insertions(+), 4 deletions(-)

diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c
index 8f112e3038dd..6cabc0fadb68 100644
--- a/drivers/input/touchscreen/himax_hx83112b.c
+++ b/drivers/input/touchscreen/himax_hx83112b.c
@@ -42,6 +42,11 @@
 
 #define HIMAX_INVALID_COORD		0xffff
 
+/* default resolution in points/mm */
+#define HIMAX_RESOLUTION		10
+
+#define HIMAX_SENSING_CHANNELS		1600
+
 struct himax_event_point {
 	__be16 x;
 	__be16 y;
@@ -54,9 +59,32 @@ struct himax_event {
 	u8 num_points;
 	u8 pad1[2];
 	u8 checksum_fix;
+	__be16 p_x;
+	__be16 p_y;
+	__be16 p_w;
+	union {
+		struct {
+			s8 tilt_x;
+			u8 hover;
+			u8 btn;
+			u8 btn2;
+			s8 tilt_y;
+			u8 pad;
+		} p_v1;
+		struct {
+			s8 tilt_x;
+			s8 tilt_y;
+			u8 status;
+			u8 pad[3];
+		} p_v2;
+	};
 } __packed;
 
-static_assert(sizeof(struct himax_event) == 56);
+#define HIMAX_PEN_HOVER		BIT(0)
+#define HIMAX_PEN_BTN		BIT(1)
+#define HIMAX_PEN_BTN2		BIT(2)
+
+static_assert(sizeof(struct himax_event) == 68);
 
 struct himax_ts_data;
 struct himax_chip {
@@ -70,9 +98,12 @@ struct himax_ts_data {
 	const struct himax_chip *chip;
 	struct gpio_desc *gpiod_rst;
 	struct input_dev *input_dev;
+	struct input_dev *pen_input_dev;
 	struct i2c_client *client;
 	struct regmap *regmap;
+	u32 pen;
 	struct touchscreen_properties props;
+	struct touchscreen_properties pen_props;
 };
 
 static const struct regmap_config himax_regmap_config = {
@@ -214,6 +245,52 @@ static int himax_input_register(struct himax_ts_data *ts)
 	return 0;
 }
 
+static int himax_pen_input_register(struct himax_ts_data *ts)
+{
+	struct input_dev *input;
+	int error;
+	u32 x_mm, y_mm;
+
+	input = devm_input_allocate_device(&ts->client->dev);
+	if (!input) {
+		dev_err(&ts->client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
+	}
+	ts->pen_input_dev = input;
+
+	input->name = "Himax Pen Input";
+
+	if (device_property_read_u32(&ts->client->dev, "touchscreen-x-mm", &x_mm) ||
+	    device_property_read_u32(&ts->client->dev, "touchscreen-y-mm", &y_mm)) {
+		input_abs_set_res(input, ABS_X, HIMAX_RESOLUTION);
+		input_abs_set_res(input, ABS_Y, HIMAX_RESOLUTION);
+	} else {
+		input_abs_set_res(input, ABS_X, HIMAX_SENSING_CHANNELS / x_mm);
+		input_abs_set_res(input, ABS_Y, HIMAX_SENSING_CHANNELS / y_mm);
+	}
+
+	input_set_capability(input, EV_ABS, ABS_X);
+	input_set_capability(input, EV_ABS, ABS_Y);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 4095, 0, 0);
+	input_set_abs_params(input, ABS_TILT_X, -60, 60, 0, 0);
+	input_set_abs_params(input, ABS_TILT_Y, -60, 60, 0, 0);
+	input_set_capability(input, EV_KEY, BTN_TOUCH);
+	input_set_capability(input, EV_KEY, BTN_STYLUS);
+	input_set_capability(input, EV_KEY, BTN_STYLUS2);
+	input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
+
+	touchscreen_parse_properties_prefix(ts->pen_input_dev, false, &ts->pen_props, "pen");
+
+	error = input_register_device(input);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"Failed to register input device: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
 static u8 himax_event_get_num_points(const struct himax_event *event)
 {
 	if (event->num_points == 0xff)
@@ -257,6 +334,45 @@ static void himax_process_event(struct himax_ts_data *ts,
 	input_sync(ts->input_dev);
 }
 
+static void himax_process_pen(struct himax_ts_data *ts,
+			      const struct himax_event *event)
+{
+	struct input_dev *dev = ts->pen_input_dev;
+	s8 tilt_x, tilt_y;
+	bool hover, btn, btn2;
+	u16 x = be16_to_cpu(event->p_x);
+	u16 y = be16_to_cpu(event->p_y);
+	bool valid = x < ts->pen_props.max_x && y < ts->pen_props.max_y;
+
+	if (ts->pen == 2) {
+		tilt_x = event->p_v2.tilt_x;
+		tilt_y = event->p_v2.tilt_y;
+		hover = event->p_v2.status & HIMAX_PEN_HOVER;
+		btn = event->p_v2.status & HIMAX_PEN_BTN;
+		btn2 = event->p_v2.status & HIMAX_PEN_BTN2;
+	} else {
+		tilt_x = event->p_v1.tilt_x;
+		tilt_y = event->p_v1.tilt_y;
+		hover = event->p_v1.hover;
+		btn = event->p_v1.btn;
+		btn2 = event->p_v1.btn2;
+	}
+
+	input_report_key(dev, BTN_TOOL_PEN, valid);
+
+	if (valid) {
+		input_report_key(dev, BTN_TOUCH, !hover);
+		touchscreen_report_pos(dev, &ts->pen_props, x, y, false);
+		input_report_abs(dev, ABS_PRESSURE, be16_to_cpu(event->p_w));
+		input_report_abs(dev, ABS_TILT_X, tilt_x);
+		input_report_abs(dev, ABS_TILT_Y, tilt_y);
+		input_report_key(dev, BTN_STYLUS, btn);
+		input_report_key(dev, BTN_STYLUS2, btn2);
+	}
+
+	input_sync(dev);
+}
+
 static bool himax_verify_checksum(struct himax_ts_data *ts,
 				  const struct himax_event *event)
 {
@@ -264,7 +380,7 @@ static bool himax_verify_checksum(struct himax_ts_data *ts,
 	int i;
 	u16 checksum = 0;
 
-	for (i = 0; i < sizeof(*event); i++)
+	for (i = 0; i <= offsetof(struct himax_event, checksum_fix); i++)
 		checksum += data[i];
 
 	if ((checksum & 0x00ff) != 0) {
@@ -293,8 +409,9 @@ static int himax_handle_input(struct himax_ts_data *ts)
 {
 	int error;
 	struct himax_event event;
+	size_t length = ts->pen ? sizeof(event) : offsetof(struct himax_event, p_x);
 
-	error = ts->chip->read_events(ts, &event, sizeof(event));
+	error = ts->chip->read_events(ts, &event, length);
 	if (error) {
 		dev_err(&ts->client->dev, "Failed to read input event: %d\n",
 			error);
@@ -305,8 +422,11 @@ static int himax_handle_input(struct himax_ts_data *ts)
 	 * Only process the current event when it has a valid checksum but
 	 * don't consider it a fatal error when it doesn't.
 	 */
-	if (himax_verify_checksum(ts, &event))
+	if (himax_verify_checksum(ts, &event)) {
 		himax_process_event(ts, &event);
+		if (ts->pen)
+			himax_process_pen(ts, &event);
+	}
 
 	return 0;
 }
@@ -368,6 +488,13 @@ static int himax_probe(struct i2c_client *client)
 	if (error)
 		return error;
 
+	device_property_read_u32(dev, "pen-present", &ts->pen);
+	if (ts->pen) {
+		error = himax_pen_input_register(ts);
+		if (error)
+			return error;
+	}
+
 	error = devm_request_threaded_irq(dev, client->irq, NULL,
 					  himax_irq_handler, IRQF_ONESHOT,
 					  client->name, ts);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2025-02-20 13:10 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-20 13:09 [PATCH 1/2] Input: of_touchscreen - support device-properties with other prefixes Dmitry Mastykin
2025-02-20 13:09 ` [PATCH 2/2] Input: himax_hx83112b - add pen support Dmitry Mastykin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).