diff --git a/package/kernel/linux/modules/input.mk b/package/kernel/linux/modules/input.mk index ef48c1c3c0c..7e67944f1ba 100644 --- a/package/kernel/linux/modules/input.mk +++ b/package/kernel/linux/modules/input.mk @@ -262,6 +262,25 @@ endef $(eval $(call KernelPackage,input-touchscreen-edt-ft5x06)) +define KernelPackage/input-touchscreen-hynitron-cst816x + SUBMENU:=$(INPUT_MODULES_MENU) + TITLE:=Hynitron CST816X touchscreen + DEPENDS:=@!LINUX_6_12 +kmod-i2c-core +kmod-input-core + KCONFIG:= \ + CONFIG_INPUT_TOUCHSCREEN=y \ + CONFIG_TOUCHSCREEN_HYNITRON_CST816X + FILES:=$(LINUX_DIR)/drivers/input/touchscreen/hynitron-cst816x.ko + AUTOLOAD:=$(call AutoProbe,hynitron-cst816x) +endef + +define KernelPackage/input-touchscreen-hynitron-cst816x/description + Kernel module for Hynitron CST816X touchscreen controller + used for 240×240 1.28-inch Round LCD Display Module. +endef + +$(eval $(call KernelPackage,input-touchscreen-hynitron-cst816x)) + + define KernelPackage/keyboard-imx SUBMENU:=$(INPUT_MODULES_MENU) TITLE:=IMX keypad support diff --git a/target/linux/generic/pending-6.18/880-01-dt-bindings-input-touchscreen-hynitron-cst816x-axes-.patch b/target/linux/generic/pending-6.18/880-01-dt-bindings-input-touchscreen-hynitron-cst816x-axes-.patch new file mode 100644 index 00000000000..1fa38facb3b --- /dev/null +++ b/target/linux/generic/pending-6.18/880-01-dt-bindings-input-touchscreen-hynitron-cst816x-axes-.patch @@ -0,0 +1,49 @@ +From 614a8ac3f9e568d6ccf4787f48b894ba8ce4b584 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 1 Oct 2026 01:57:03 +0100 +Subject: [PATCH v4 1/5] dt-bindings: input: touchscreen: hynitron,cst816x: axes + and panel + +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 +--- +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(-) + +--- 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 = , , , , + ; ++ touchscreen-swapped-x-y; + }; + }; + diff --git a/target/linux/generic/pending-6.18/880-02-Input-hynitron-cst816x-respect-touchscreen-DT-proper.patch b/target/linux/generic/pending-6.18/880-02-Input-hynitron-cst816x-respect-touchscreen-DT-proper.patch new file mode 100644 index 00000000000..a17faf87237 --- /dev/null +++ b/target/linux/generic/pending-6.18/880-02-Input-hynitron-cst816x-respect-touchscreen-DT-proper.patch @@ -0,0 +1,58 @@ +From 9e3cca6e6f43c886c58d9258fca4ad19cff066b4 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 1 Oct 2026 01:01:51 +0100 +Subject: [PATCH v4 2/5] Input: hynitron-cst816x: respect touchscreen DT + properties + +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 +--- +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(-) + +--- a/drivers/input/touchscreen/hynitron-cst816x.c ++++ b/drivers/input/touchscreen/hynitron-cst816x.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -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 + 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 ir + 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, diff --git a/target/linux/generic/pending-6.18/880-03-Input-hynitron-cst816x-release-gesture-keys.patch b/target/linux/generic/pending-6.18/880-03-Input-hynitron-cst816x-release-gesture-keys.patch new file mode 100644 index 00000000000..426d6265227 --- /dev/null +++ b/target/linux/generic/pending-6.18/880-03-Input-hynitron-cst816x-release-gesture-keys.patch @@ -0,0 +1,163 @@ +From 5312d67200e3251b2be08aef0a726d50d94fadde Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 5 Oct 2026 20:22:23 +0100 +Subject: [PATCH v4 3/5] Input: hynitron-cst816x: release gesture keys + +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 +--- +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(-) + +--- a/drivers/input/touchscreen/hynitron-cst816x.c ++++ b/drivers/input/touchscreen/hynitron-cst816x.c +@@ -39,28 +39,40 @@ static int cst816x_parse_keycodes(struct + { + 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(str + 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 + 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 ir + 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); + diff --git a/target/linux/generic/pending-6.18/880-04-Input-hynitron-cst816x-time-out-gesture-key-release.patch b/target/linux/generic/pending-6.18/880-04-Input-hynitron-cst816x-time-out-gesture-key-release.patch new file mode 100644 index 00000000000..2cc81f9f906 --- /dev/null +++ b/target/linux/generic/pending-6.18/880-04-Input-hynitron-cst816x-time-out-gesture-key-release.patch @@ -0,0 +1,154 @@ +From d73d26d8c9d75fa230e3dd64058acb65f45da64d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 5 Oct 2026 20:22:23 +0100 +Subject: [PATCH v4 4/5] Input: hynitron-cst816x: time out gesture key release + +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 +--- +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(-) + +--- a/drivers/input/touchscreen/hynitron-cst816x.c ++++ b/drivers/input/touchscreen/hynitron-cst816x.c +@@ -15,9 +15,12 @@ + #include + #include + #include ++#include ++#include + + #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 + 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 + 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_clie + 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_clie + 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); diff --git a/target/linux/generic/pending-6.18/880-05-Input-hynitron-cst816x-set-INPUT_PROP_DIRECT.patch b/target/linux/generic/pending-6.18/880-05-Input-hynitron-cst816x-set-INPUT_PROP_DIRECT.patch new file mode 100644 index 00000000000..5d694c502c9 --- /dev/null +++ b/target/linux/generic/pending-6.18/880-05-Input-hynitron-cst816x-set-INPUT_PROP_DIRECT.patch @@ -0,0 +1,29 @@ +From ff91fc6f203d4442d555597cdb455b476af9da50 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 5 Oct 2026 21:45:37 +0100 +Subject: [PATCH v4 5/5] Input: hynitron-cst816x: set INPUT_PROP_DIRECT + +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 +--- +v4: new patch + + drivers/input/touchscreen/hynitron-cst816x.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/input/touchscreen/hynitron-cst816x.c ++++ b/drivers/input/touchscreen/hynitron-cst816x.c +@@ -157,6 +157,7 @@ static int cst816x_register_input(struct + 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;