mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-14 06:38:29 +04:00
kernel: modules: package driver for Hynitron CST816x touch sensor
Package kernel driver for the Hynitron CST816x touch sensor, found on ST7789V-based 240x240 px MIPI-DBI display of the Adtran SmartRG SDG-9000. Import pending patches improving the driver. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
1 parent
dc7acc1888
commit
2bba9c1ba5
6 files changed
+472
No files matched your search
@@ -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
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
From 614a8ac3f9e568d6ccf4787f48b894ba8ce4b584 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <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(-)
|
||||
|
||||
--- 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;
|
||||
};
|
||||
};
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
From 9e3cca6e6f43c886c58d9258fca4ad19cff066b4 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <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(-)
|
||||
|
||||
--- 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
|
||||
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,
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
From 5312d67200e3251b2be08aef0a726d50d94fadde Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <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(-)
|
||||
|
||||
--- 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);
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
From d73d26d8c9d75fa230e3dd64058acb65f45da64d Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <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(-)
|
||||
|
||||
--- 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
|
||||
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);
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
From ff91fc6f203d4442d555597cdb455b476af9da50 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
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 <daniel@makrotopia.org>
|
||||
---
|
||||
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;
|
||||
Reference in new issue
Block a user