* [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes and panel
2026-10-05 21:10 [PATCH v4 0/5] Input: hynitron-cst816x: axes and gesture keys Daniel Golle
@ 2026-10-05 21:11 ` Daniel Golle
2026-10-06 2:51 ` Rob Herring
2026-10-05 21:11 ` [PATCH v4 2/5] Input: hynitron-cst816x: respect touchscreen DT properties Daniel Golle
` (3 subsequent siblings)
4 siblings, 1 reply; 7+ messages in thread
From: Daniel Golle @ 2026-10-05 21:11 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Daniel Golle, Uwe Kleine-König, Oleh Kuzhylnyi, linux-input,
devicetree, linux-kernel
The chip hands out coordinates in its own frame and knows nothing of
the panel it is glued to, so how it is oriented against that panel,
which coordinate range the assembly reports and how noisy it is are
properties of the board. Reference touchscreen.yaml and let its
properties through, among them the 'panel' phandle naming the panel a
controller is mounted on, which asks for the two to be power sequenced
together.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v3:
- describe the whole of touchscreen.yaml with unevaluatedProperties
(Krzysztof Kozlowski)
v2:
- allow the min, size and fuzz properties as well (Sashiko AI review)
- allow the 'panel' phandle
- justify the change in the commit message (Conor Dooley)
.../bindings/input/touchscreen/hynitron,cst816x.yaml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml
index 72d4da636881e..72b1bbff6e57b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/hynitron,cst816x.yaml
@@ -41,7 +41,10 @@ required:
- reg
- interrupts
-additionalProperties: false
+unevaluatedProperties: false
+
+allOf:
+ - $ref: touchscreen.yaml#
examples:
- |
@@ -59,6 +62,7 @@ examples:
reset-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
linux,keycodes = <KEY_UP>, <KEY_DOWN>, <KEY_LEFT>, <KEY_RIGHT>,
<BTN_TOOL_TRIPLETAP>;
+ touchscreen-swapped-x-y;
};
};
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes and panel
2026-10-05 21:11 ` [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes and panel Daniel Golle
@ 2026-10-06 2:51 ` Rob Herring
0 siblings, 0 replies; 7+ messages in thread
From: Rob Herring @ 2026-10-06 2:51 UTC (permalink / raw)
To: Daniel Golle
Cc: Dmitry Torokhov, Krzysztof Kozlowski, Conor Dooley,
Uwe Kleine-König, Oleh Kuzhylnyi, linux-input, devicetree,
linux-kernel
On Mon, Oct 05, 2026 at 10:11:10PM +0100, Daniel Golle wrote:
> The chip hands out coordinates in its own frame and knows nothing of
> the panel it is glued to, so how it is oriented against that panel,
> which coordinate range the assembly reports and how noisy it is are
> properties of the board. Reference touchscreen.yaml and let its
> properties through, among them the 'panel' phandle naming the panel a
> controller is mounted on, which asks for the two to be power sequenced
> together.
>
> Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Missing Krzysztof's Reviewed-by
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 2/5] Input: hynitron-cst816x: respect touchscreen DT properties
2026-10-05 21:10 [PATCH v4 0/5] Input: hynitron-cst816x: axes and gesture keys Daniel Golle
2026-10-05 21:11 ` [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes and panel Daniel Golle
@ 2026-10-05 21:11 ` Daniel Golle
2026-10-05 21:11 ` [PATCH v4 3/5] Input: hynitron-cst816x: release gesture keys Daniel Golle
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Daniel Golle @ 2026-10-05 21:11 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Daniel Golle, Uwe Kleine-König, Oleh Kuzhylnyi, linux-input,
devicetree, linux-kernel
Parse common touchscreen properties and use touchscreen_report_pos()
instead of reporting raw absolute position.
This makes the driver respect the touchscreen-min-x/y,
touchscreen-size-x/y, touchscreen-fuzz-x/y, touchscreen-inverted-x/y
and touchscreen-swapped-x-y properties.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v2:
- name all the properties the parser honours, no functional change
drivers/input/touchscreen/hynitron-cst816x.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
index 47d9cd7412d1b..865c5a767ba01 100644
--- a/drivers/input/touchscreen/hynitron-cst816x.c
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -11,6 +11,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/input/touchscreen.h>
#include <linux/unaligned.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -31,6 +32,7 @@ struct cst816x_priv {
struct input_dev *input;
unsigned int keycode[CST816X_NUM_KEYS];
unsigned int keycodemax;
+ struct touchscreen_properties prop;
};
static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
@@ -142,6 +144,7 @@ static int cst816x_register_input(struct cst816x_priv *priv)
input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
+ touchscreen_parse_properties(priv->input, false, &priv->prop);
priv->input->keycode = priv->keycode;
priv->input->keycodesize = sizeof(priv->keycode[0]);
@@ -173,8 +176,8 @@ static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
if (!cst816x_process_touch(priv, &tch))
return IRQ_HANDLED;
- input_report_abs(priv->input, ABS_X, tch.abs_x);
- input_report_abs(priv->input, ABS_Y, tch.abs_y);
+ touchscreen_report_pos(priv->input, &priv->prop,
+ tch.abs_x, tch.abs_y, false);
if (tch.gest)
input_report_key(priv->input,
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v4 3/5] Input: hynitron-cst816x: release gesture keys
2026-10-05 21:10 [PATCH v4 0/5] Input: hynitron-cst816x: axes and gesture keys Daniel Golle
2026-10-05 21:11 ` [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes and panel Daniel Golle
2026-10-05 21:11 ` [PATCH v4 2/5] Input: hynitron-cst816x: respect touchscreen DT properties Daniel Golle
@ 2026-10-05 21:11 ` Daniel Golle
2026-10-05 21:12 ` [PATCH v4 4/5] Input: hynitron-cst816x: time out gesture key release Daniel Golle
2026-10-05 21:12 ` [PATCH v4 5/5] Input: hynitron-cst816x: set INPUT_PROP_DIRECT Daniel Golle
4 siblings, 0 replies; 7+ messages in thread
From: Daniel Golle @ 2026-10-05 21:11 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Daniel Golle, Uwe Kleine-König, Oleh Kuzhylnyi, linux-input,
devicetree, linux-kernel
The gesture key is reported with the value of the touch flag, so it
stays pressed once the controller stops reporting the gesture code
while the finger is still down. Report the press on its own and
release the keys the input core still holds down on the first report
that carries no gesture code. Report a key only for the gesture codes
the binding names: the controller also sends codes such as single
click, and the index fallback aliased those onto the long-press
keycode. Keycodes above KEY_MAX are rejected, as that release looks
the key state up in the input core's key bitmap.
Fixes: c87a819bec86 ("Input: add driver for Hynitron CST816x series")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v4:
- map only the documented gesture codes to keys, as single click
aliased onto the long-press keycode (Oleh Kuzhylnyi)
- read each keycode once in the release loop, so the key it tests is
the key it releases (Sashiko AI review)
v2:
- reject keycodes above KEY_MAX and publish keycodemax only once the
whole array validates (Sashiko AI review)
drivers/input/touchscreen/hynitron-cst816x.c | 87 +++++++++++++-------
1 file changed, 55 insertions(+), 32 deletions(-)
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
index 865c5a767ba01..2d8f0b78a3a8a 100644
--- a/drivers/input/touchscreen/hynitron-cst816x.c
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -39,28 +39,40 @@ static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
{
int count;
int error;
+ int i;
- if (device_property_present(dev, "linux,keycodes")) {
- count = device_property_count_u32(dev, "linux,keycodes");
- if (count < 0) {
- error = count;
- dev_err(dev, "failed to count keys: %d\n", error);
- return error;
- } else if (count > ARRAY_SIZE(priv->keycode)) {
- dev_err(dev, "too many keys defined: %d\n", count);
- return -EINVAL;
- }
- priv->keycodemax = count;
-
- error = device_property_read_u32_array(dev, "linux,keycodes",
- priv->keycode,
- priv->keycodemax);
- if (error) {
- dev_err(dev, "failed to read keycodes: %d\n", error);
- return error;
- }
+ if (!device_property_present(dev, "linux,keycodes"))
+ return 0;
+
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count < 0) {
+ error = count;
+ dev_err(dev, "failed to count keys: %d\n", error);
+ return error;
+ }
+
+ if (count > ARRAY_SIZE(priv->keycode)) {
+ dev_err(dev, "too many keys defined: %d\n", count);
+ return -EINVAL;
+ }
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ priv->keycode, count);
+ if (error) {
+ dev_err(dev, "failed to read keycodes: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (priv->keycode[i] <= KEY_MAX)
+ continue;
+
+ dev_err(dev, "keycode %u out of range\n", priv->keycode[i]);
+ return -EINVAL;
}
+ priv->keycodemax = count;
+
return 0;
}
@@ -94,24 +106,19 @@ static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
return 0;
}
-static u8 cst816x_gest_idx(u8 gest)
+static unsigned int cst816x_gest_keycode(struct cst816x_priv *priv, u8 gest)
{
- u8 index;
-
switch (gest) {
case 0x01: /* Slide up gesture */
case 0x02: /* Slide down gesture */
case 0x03: /* Slide left gesture */
case 0x04: /* Slide right gesture */
- index = gest;
- break;
+ return priv->keycode[gest - 1];
case 0x0c: /* Long press gesture */
+ return priv->keycode[CST816X_NUM_KEYS - 1];
default:
- index = CST816X_NUM_KEYS;
- break;
+ return KEY_RESERVED;
}
-
- return index - 1;
}
static bool cst816x_process_touch(struct cst816x_priv *priv,
@@ -168,10 +175,25 @@ static void cst816x_reset(struct cst816x_priv *priv)
msleep(100);
}
+static void cst816x_release_keys(struct cst816x_priv *priv)
+{
+ unsigned int key;
+ unsigned int i;
+
+ for (i = 0; i < priv->keycodemax; i++) {
+ key = priv->keycode[i];
+ if (!test_bit(key, priv->input->key))
+ continue;
+
+ input_report_key(priv->input, key, 0);
+ }
+}
+
static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
{
struct cst816x_priv *priv = cookie;
struct cst816x_touch tch;
+ unsigned int key;
if (!cst816x_process_touch(priv, &tch))
return IRQ_HANDLED;
@@ -179,10 +201,11 @@ static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
touchscreen_report_pos(priv->input, &priv->prop,
tch.abs_x, tch.abs_y, false);
- if (tch.gest)
- input_report_key(priv->input,
- priv->keycode[cst816x_gest_idx(tch.gest)],
- tch.active);
+ key = cst816x_gest_keycode(priv, tch.gest);
+ if (key != KEY_RESERVED)
+ input_report_key(priv->input, key, 1);
+ else
+ cst816x_release_keys(priv);
input_report_key(priv->input, BTN_TOUCH, tch.active);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v4 4/5] Input: hynitron-cst816x: time out gesture key release
2026-10-05 21:10 [PATCH v4 0/5] Input: hynitron-cst816x: axes and gesture keys Daniel Golle
` (2 preceding siblings ...)
2026-10-05 21:11 ` [PATCH v4 3/5] Input: hynitron-cst816x: release gesture keys Daniel Golle
@ 2026-10-05 21:12 ` Daniel Golle
2026-10-05 21:12 ` [PATCH v4 5/5] Input: hynitron-cst816x: set INPUT_PROP_DIRECT Daniel Golle
4 siblings, 0 replies; 7+ messages in thread
From: Daniel Golle @ 2026-10-05 21:12 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Daniel Golle, Uwe Kleine-König, Oleh Kuzhylnyi, linux-input,
devicetree, linux-kernel
The controller reports a gesture code once and can then stay quiet
until the next touch, which leaves the gesture key pressed for as long
as the panel is left alone. Release the gesture keys 40 ms after the
last report that carried a gesture code, so that the release comes
from whichever happens first, the timeout or a report without a
gesture code. The 40 ms matches TSC200X_PENUP_TIME_MS, chosen there
for the same want of a lift event from the controller, and has to stay
above the interval between consecutive reports of a held gesture.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
v4: follow the keycode lookup and the single read of patch 3
v3: use timer_shutdown_sync() in the devres teardown action
(Sashiko AI review)
v2: skip the release when the interrupt handler re-armed the timer
while the timer callback waited for the lock (Sashiko AI review)
drivers/input/touchscreen/hynitron-cst816x.c | 52 ++++++++++++++++++--
1 file changed, 49 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
index 2d8f0b78a3a8a..7ef3e17a65f77 100644
--- a/drivers/input/touchscreen/hynitron-cst816x.c
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -15,9 +15,12 @@
#include <linux/unaligned.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
#define CST816X_RD_REG 0x01
#define CST816X_NUM_KEYS 5
+#define CST816X_GEST_HOLD_MS 40
struct cst816x_touch {
u8 gest;
@@ -32,6 +35,9 @@ struct cst816x_priv {
struct input_dev *input;
unsigned int keycode[CST816X_NUM_KEYS];
unsigned int keycodemax;
+ struct timer_list release_timer;
+ /* lock keeps the timeout out of the middle of a report */
+ spinlock_t lock;
struct touchscreen_properties prop;
};
@@ -175,8 +181,9 @@ static void cst816x_reset(struct cst816x_priv *priv)
msleep(100);
}
-static void cst816x_release_keys(struct cst816x_priv *priv)
+static bool cst816x_release_keys(struct cst816x_priv *priv)
{
+ bool released = false;
unsigned int key;
unsigned int i;
@@ -186,34 +193,67 @@ static void cst816x_release_keys(struct cst816x_priv *priv)
continue;
input_report_key(priv->input, key, 0);
+ released = true;
}
+
+ return released;
+}
+
+static void cst816x_release_timeout(struct timer_list *t)
+{
+ struct cst816x_priv *priv = timer_container_of(priv, t, release_timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* a re-arm while this waited for the lock supersedes the timeout */
+ if (!timer_pending(&priv->release_timer) && cst816x_release_keys(priv))
+ input_sync(priv->input);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
}
static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
{
struct cst816x_priv *priv = cookie;
struct cst816x_touch tch;
+ unsigned long flags;
unsigned int key;
if (!cst816x_process_touch(priv, &tch))
return IRQ_HANDLED;
+ spin_lock_irqsave(&priv->lock, flags);
+
touchscreen_report_pos(priv->input, &priv->prop,
tch.abs_x, tch.abs_y, false);
key = cst816x_gest_keycode(priv, tch.gest);
- if (key != KEY_RESERVED)
+ if (key != KEY_RESERVED) {
input_report_key(priv->input, key, 1);
- else
+ mod_timer(&priv->release_timer,
+ jiffies + msecs_to_jiffies(CST816X_GEST_HOLD_MS));
+ } else {
+ timer_delete(&priv->release_timer);
cst816x_release_keys(priv);
+ }
input_report_key(priv->input, BTN_TOUCH, tch.active);
input_sync(priv->input);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return IRQ_HANDLED;
}
+static void cst816x_timer_stop(void *data)
+{
+ struct cst816x_priv *priv = data;
+
+ timer_shutdown_sync(&priv->release_timer);
+}
+
static int cst816x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -225,6 +265,8 @@ static int cst816x_probe(struct i2c_client *client)
return -ENOMEM;
priv->client = client;
+ spin_lock_init(&priv->lock);
+ timer_setup(&priv->release_timer, cst816x_release_timeout, 0);
priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset))
@@ -242,6 +284,10 @@ static int cst816x_probe(struct i2c_client *client)
if (error)
return dev_err_probe(dev, error, "input register failed\n");
+ error = devm_add_action_or_reset(dev, cst816x_timer_stop, priv);
+ if (error)
+ return error;
+
error = devm_request_threaded_irq(dev, client->irq,
NULL, cst816x_irq_cb, IRQF_ONESHOT,
dev_driver_string(dev), priv);
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v4 5/5] Input: hynitron-cst816x: set INPUT_PROP_DIRECT
2026-10-05 21:10 [PATCH v4 0/5] Input: hynitron-cst816x: axes and gesture keys Daniel Golle
` (3 preceding siblings ...)
2026-10-05 21:12 ` [PATCH v4 4/5] Input: hynitron-cst816x: time out gesture key release Daniel Golle
@ 2026-10-05 21:12 ` Daniel Golle
4 siblings, 0 replies; 7+ messages in thread
From: Daniel Golle @ 2026-10-05 21:12 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Daniel Golle, Uwe Kleine-König, Oleh Kuzhylnyi, linux-input,
devicetree, linux-kernel
The sensor sits on the panel, so the coordinates it reports map
straight onto the display. Without either direct or pointer set,
event-codes.rst leaves userspace to deduce the device type from the
emitted event types, where ABS_X, ABS_Y and BTN_TOUCH read as a
touchpad and a touch becomes relative pointer motion.
Fixes: c87a819bec86 ("Input: add driver for Hynitron CST816x series")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/input/touchscreen/hynitron-cst816x.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
index 7ef3e17a65f77..040ee3c2983ef 100644
--- a/drivers/input/touchscreen/hynitron-cst816x.c
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -157,6 +157,7 @@ static int cst816x_register_input(struct cst816x_priv *priv)
input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
+ __set_bit(INPUT_PROP_DIRECT, priv->input->propbit);
touchscreen_parse_properties(priv->input, false, &priv->prop);
priv->input->keycode = priv->keycode;
--
2.56.0
^ permalink raw reply [flat|nested] 7+ messages in thread