* [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte)
@ 2026-07-30 20:18 Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty, Krzysztof Kozlowski
The zinitix family of touchscreens support at least three modes, called
0, 1, and 2. At least some digitizers (including, but not limited to
ZT7548) are able to support multiple modes. Currently, the driver in
linux supports mode 2 only. This series aims to add support for modes 0
and 1, accompanied with necessary architectural changes.
Among other things, perhaps the biggest difference between multiple
modes is how the touch report schema is laid out. Modes may skip
reporting certain properties such as touch width and pressure. For more
implementation details, the android driver [1] can be referred to, which
was also the primary reference material for these changes.
The last patch is for the Samsung Galaxy J6 (samsung-j6lte), which has a
zinitix touchscreen digitizer. By default, mode 2 is assumed for the
touchscreen, however the downstream kernel driver [1] for this device
uses mode 0 by default. This creates an issue with aftermarket
digitizers where mode 2 implementation isn't available simply because
it's not required by the driver downstream.
This last patch needs to be accepted into next only when the former
patches are in next.
[1] https://github.com/samsungexynos7870/android_kernel_samsung_exynos7870/blob/master/drivers/input/touchscreen/zinitix/zinitix_zt75xx_ts.c
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
Changes in v3:
- Add missing review trailers from v1
- Link to v2: https://patch.msgid.link/20260731-zinitix-modes-v2-0-ffe2ec9a9031@disroot.org
Changes in v2:
- Change condition for calling zinitix_report_finger() (Dmitry Torokhov)
- Use function pointer for read_status_mode* switching (Dmitry Torokhov)
- Link to v1: https://patch.msgid.link/20260724-zinitix-modes-v1-0-f6df7d86a878@disroot.org
---
Kaustabh Chakraborty (5):
Input: zinitix - check all available fingers for every touch event
Input: zinitix - do not ignore non-moving fingers
Input: zinitix - add support for modes 0 and 1
dt-bindings: input/ts/zinitix: document mode 0
arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen
.../bindings/input/touchscreen/zinitix,bt400.yaml | 4 +-
arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 2 +
drivers/input/touchscreen/zinitix.c | 141 +++++++++++++++++++--
3 files changed, 132 insertions(+), 15 deletions(-)
---
base-commit: 290aaf24a551d5a0dce037e3fab30820f9113a10
change-id: 20260723-zinitix-modes-9c4d409b9ee3
Best regards,
--
Kaustabh Chakraborty <kauschluss@disroot.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
@ 2026-07-30 20:18 ` Kaustabh Chakraborty
2026-07-30 20:31 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
` (3 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
When this initial driver was first added to tree, that is, in commit
26822652c85e ("Input: add zinitix touchscreen driver"), the touch_event
struct had a field called finger_cnt. It was supposed to report how many
fingers are touching the screen.
But then, in commit e941dc13fd37 ("Input: zinitix - do not report shadow
fingers"), some touchscreens reportedly exposed a bit mask for the
fingers, instead of the count. So the code was changed to bitwise
iteration.
With my testing on the ZT7548 touchscreen of the Galaxy J6, I find the
former to be true. This shows that there's two valid methods depending
on what hardware the driver is made to work on.
One solution is to implement both methods, and use some flag to select
between the two. However, this introduces more implementation overhead,
and a possibility of regression on devices the driver is expected to work.
Instead, unconditionally check all fingers. The finger_mask field is now
left unused, thus serving as padding bytes in the struct. For each
finger, zinitix_report_finger() is called if the status reports the
SUB_BIT_EXIST bit, so phantom fingers are not going to be a thing.
Moreover, the android driver [1] does exactly that, so it's a tried
method of implementation.
Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 0c36765bd79f..3421b8ffb19b 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -445,7 +445,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
struct bt541_ts_data *bt541 = bt541_handler;
struct i2c_client *client = bt541->client;
struct touch_event touch_event;
- unsigned long finger_mask;
__le16 icon_events;
int error;
int i;
@@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
zinitix_report_keys(bt541, le16_to_cpu(icon_events));
}
- finger_mask = touch_event.finger_mask;
- for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
+ for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
const struct point_coord *p = &touch_event.point_coord[i];
/* Only process contacts that are actually reported */
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
@ 2026-07-30 20:18 ` Kaustabh Chakraborty
2026-07-30 20:31 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
` (2 subsequent siblings)
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
With the ZT7548 touchscreen present in the Galaxy J6, multitouch does not
work reliably. This is due to the fact that the driver reports fingers
only when their state is changed, so it's either placed against the
screen, moved, or drawn away from the screen.
The function which is responsible for this is zinitix_report_finger().
This function is called from the IRQ handler, under the following
condition:
if (p->sub_status & SUB_BIT_EXIST)
zinitix_report_finger(bt541, i, p);
This implies and ensures that every valid finger must have the
SUB_BIT_EXIST flag.
However, at the beginning of the function, it refuses to recognize any
finger if it has none of SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE. This
excludes fingers in reports which do not move from the position since
the previous interrupt. Add SUB_BIT_EXIST to the list of valid bits.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 3421b8ffb19b..a0a89d25e25b 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
u16 x, y;
if (unlikely(!(p->sub_status &
- (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
+ (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
p->sub_status);
return;
@@ -473,7 +473,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
const struct point_coord *p = &touch_event.point_coord[i];
/* Only process contacts that are actually reported */
- if (p->sub_status & SUB_BIT_EXIST)
+ if (p->sub_status)
zinitix_report_finger(bt541, i, p);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
@ 2026-07-30 20:18 ` Kaustabh Chakraborty
2026-07-30 20:29 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
4 siblings, 1 reply; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
Zinitix touchscreens have three modes, numbered 0 to 2. The driver
implements mode 2, and leaves out modes 0 and 1. The difference in the
touchscreen modes is the schema of the event data.
Implement modes 0 and 1 in the driver, along with their event structs.
Maintain a common, canonical event struct which is to be the superset of
the mode-specific structs. With that, introduce functions to convert the
mode event info to the canonical format.
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
drivers/input/touchscreen/zinitix.c | 133 +++++++++++++++++++++++++++++++++---
1 file changed, 125 insertions(+), 8 deletions(-)
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index a0a89d25e25b..aafd0b7d8edb 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -145,7 +145,37 @@ struct point_coord {
u8 angle;
};
+struct point_coord_mode0 {
+ __le16 x;
+ __le16 y;
+ u8 width;
+ u8 sub_status;
+};
+
struct touch_event {
+ __le16 status;
+ __le16 event_flag;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode0 {
+ __le16 status;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode1 {
+ __le16 status;
+ __le16 event_flag;
+ u8 finger_mask;
+ u8 time_stamp;
+ struct point_coord_mode0 point_coord[MAX_SUPPORTED_FINGER_NUM];
+};
+
+struct touch_event_mode2 {
__le16 status;
u8 finger_mask;
u8 time_stamp;
@@ -165,6 +195,7 @@ struct bt541_ts_data {
u16 firmware_version;
u16 regdata_version;
u16 icon_status_reg;
+ int (*read_point_status)(struct bt541_ts_data *bt541, struct touch_event *event);
};
static int zinitix_read_data(struct i2c_client *client,
@@ -440,6 +471,87 @@ static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
bt541->keycodes[i], icon_events & BIT(i));
}
+static int zinitix_read_point_status_mode0(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode0 event_mode0;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode0, sizeof(struct touch_event_mode0));
+ if (ret)
+ return ret;
+
+ event->status = event_mode0.status;
+ event->finger_mask = event_mode0.finger_mask;
+ event->time_stamp = event_mode0.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode0.point_coord); i++) {
+ event->point_coord[i].x = event_mode0.point_coord[i].x;
+ event->point_coord[i].y = event_mode0.point_coord[i].y;
+ event->point_coord[i].width = event_mode0.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode0.point_coord[i].sub_status;
+ }
+
+ return 0;
+}
+
+static int zinitix_read_point_status_mode1(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode1 event_mode1;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode1, sizeof(struct touch_event_mode1));
+ if (ret)
+ return ret;
+
+ event->status = event_mode1.status;
+ event->event_flag = event_mode1.event_flag;
+ event->finger_mask = event_mode1.finger_mask;
+ event->time_stamp = event_mode1.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode1.point_coord); i++) {
+ event->point_coord[i].x = event_mode1.point_coord[i].x;
+ event->point_coord[i].y = event_mode1.point_coord[i].y;
+ event->point_coord[i].width = event_mode1.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode1.point_coord[i].sub_status;
+ }
+
+ return 0;
+}
+
+static int zinitix_read_point_status_mode2(struct bt541_ts_data *bt541,
+ struct touch_event *event)
+{
+ struct touch_event_mode2 event_mode2;
+ int ret;
+ int i;
+
+ ret = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
+ &event_mode2, sizeof(struct touch_event_mode2));
+ if (ret)
+ return ret;
+
+ event->status = event_mode2.status;
+ event->finger_mask = event_mode2.finger_mask;
+ event->time_stamp = event_mode2.time_stamp;
+
+ for (i = 0; i < ARRAY_SIZE(event_mode2.point_coord); i++) {
+ event->point_coord[i].x = event_mode2.point_coord[i].x;
+ event->point_coord[i].y = event_mode2.point_coord[i].y;
+ event->point_coord[i].width = event_mode2.point_coord[i].width;
+ event->point_coord[i].sub_status = event_mode2.point_coord[i].sub_status;
+ event->point_coord[i].minor_width = event_mode2.point_coord[i].minor_width;
+ event->point_coord[i].angle = event_mode2.point_coord[i].angle;
+ }
+
+ return 0;
+}
+
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
{
struct bt541_ts_data *bt541 = bt541_handler;
@@ -451,8 +563,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
memset(&touch_event, 0, sizeof(struct touch_event));
- error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
- &touch_event, sizeof(struct touch_event));
+ error = bt541->read_point_status(bt541, &touch_event);
if (error) {
dev_err(&client->dev, "Failed to read in touchpoint struct\n");
goto out;
@@ -682,13 +793,19 @@ static int zinitix_ts_probe(struct i2c_client *client)
bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
}
- if (bt541->zinitix_mode != 2) {
- /*
- * If there are devices that don't support mode 2, support
- * for other modes (0, 1) will be needed.
- */
+ switch (bt541->zinitix_mode) {
+ case 0:
+ bt541->read_point_status = zinitix_read_point_status_mode0;
+ break;
+ case 1:
+ bt541->read_point_status = zinitix_read_point_status_mode1;
+ break;
+ case 2:
+ bt541->read_point_status = zinitix_read_point_status_mode2;
+ break;
+ default:
dev_err(&client->dev,
- "Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
+ "Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
bt541->zinitix_mode);
return -EINVAL;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 4/5] dt-bindings: input/ts/zinitix: document mode 0
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
` (2 preceding siblings ...)
2026-07-30 20:18 ` [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
@ 2026-07-30 20:18 ` Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
4 siblings, 0 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty, Krzysztof Kozlowski
Zinitix touchscreens support three modes, numbered 0 to 2. These modes
differ based on their event report schema.
The devicetree schema does not mention mode 0, thus does not consider it
as a valid state. Add it.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
.../devicetree/bindings/input/touchscreen/zinitix,bt400.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
index f1ce837b16df..9b51212ea9b9 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
+++ b/Documentation/devicetree/bindings/input/touchscreen/zinitix,bt400.yaml
@@ -76,9 +76,9 @@ properties:
zinitix,mode:
description: Mode of reporting touch points. Some modes may not work
with a particular ts firmware for unknown reasons. Available modes are
- 1 and 2. Mode 2 is the default and preferred.
+ 0, 1, and 2. Mode 2 is the default and preferred.
$ref: /schemas/types.yaml#/definitions/uint32
- enum: [1, 2]
+ enum: [0, 1, 2]
linux,keycodes:
description:
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
` (3 preceding siblings ...)
2026-07-30 20:18 ` [PATCH v3 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
@ 2026-07-30 20:18 ` Kaustabh Chakraborty
4 siblings, 0 replies; 9+ messages in thread
From: Kaustabh Chakraborty @ 2026-07-30 20:18 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Michael Srba, Linus Walleij, Peter Griffin, Alim Akhtar
Cc: linux-input, linux-kernel, devicetree, linux-arm-kernel,
linux-samsung-soc, Kaustabh Chakraborty
The ZT7548 chip in the Galaxy J6 is actually able to support mode 2 (the
recommended mode) just fine.
However, the downstream kernel driver utilizes mode 0. This creates a
problem in the aftermarket world where fake touch digitizers only
implement the bare minimum functionality, as used by the downstream
driver, to compromise on cost, which leads to such chips implementing
mode 0 only. To ensure touch works on those devices, set the default
mode to 0.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Signed-off-by: Kaustabh Chakraborty <kauschluss@disroot.org>
---
arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
index de30d0970336..bd8f798c9810 100644
--- a/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
+++ b/arch/arm64/boot/dts/exynos/exynos7870-j6lte.dts
@@ -424,6 +424,8 @@ touchscreen@20 {
touchscreen-size-y = <1480>;
vdd-supply = <&vdd_ldo34>;
+
+ zinitix,mode = <0>;
};
};
--
2.54.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1
2026-07-30 20:18 ` [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
@ 2026-07-30 20:29 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-30 20:29 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: devicetree, robh, linux-input, conor+dt, dmitry.torokhov
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Race condition in probe leading to NULL pointer dereference in IRQ handler
--
--- Patch [3]: [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1 ---
commit d8a438a256bc9e4876b89aa10b882e0dd303cf72
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - add support for modes 0 and 1
The commit adds support for touch coordinate modes 0 and 1 for zinitix
touchscreens. It abstracts the reading function into a function pointer
read_point_status inside the device's private struct, assigned based on
the zinitix,mode property.
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index a0a89d25e25bb..aafd0b7d8edbd 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -451,8 +563,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
>
> memset(&touch_event, 0, sizeof(struct touch_event));
>
> - error = zinitix_read_data(bt541->client, ZINITIX_POINT_STATUS_REG,
> - &touch_event, sizeof(struct touch_event));
> + error = bt541->read_point_status(bt541, &touch_event);
[Severity: High]
Is there a possibility of a NULL pointer dereference here?
In zinitix_ts_probe(), zinitix_init_input_dev() is called before the
read_point_status function pointer is assigned.
zinitix_init_input_dev() registers the input device, making it visible to
userspace. If a userspace process opens the device immediately and an interrupt
fires, zinitix_ts_irq_handler() could run and dereference this function pointer
while it is still NULL.
> if (error) {
> dev_err(&client->dev, "Failed to read in touchpoint struct\n");
> goto out;
[ ... ]
> @@ -682,13 +793,19 @@ static int zinitix_ts_probe(struct i2c_client *client)
> bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
> }
>
> - if (bt541->zinitix_mode != 2) {
> - /*
> - * If there are devices that don't support mode 2, support
> - * for other modes (0, 1) will be needed.
> - */
> + switch (bt541->zinitix_mode) {
> + case 0:
> + bt541->read_point_status = zinitix_read_point_status_mode0;
> + break;
> + case 1:
> + bt541->read_point_status = zinitix_read_point_status_mode1;
> + break;
> + case 2:
> + bt541->read_point_status = zinitix_read_point_status_mode2;
> + break;
> + default:
> dev_err(&client->dev,
> - "Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
> + "Malformed zinitix,mode property, must be 0, 1, or 2 (supplied: %d)\n",
> bt541->zinitix_mode);
> return -EINVAL;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-zinitix-modes-v3-0-2c8de712997a@disroot.org?part=3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers
2026-07-30 20:18 ` [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
@ 2026-07-30 20:31 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-30 20:31 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: devicetree, dmitry.torokhov, linux-input, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The patch incorrectly relaxes the validation of touch contacts, turning an AND condition into an OR condition, which risks processing stale slots as ghost touches.
Pre-existing issues:
- [High] The input device is registered and exposed to the system before its private data is fully initialized, causing it to be opened with uninitialized hardware settings.
--
--- Patch [2]: [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers ---
commit 454d687d20badd95d32dd2be0a6d7cb81eb6b592
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - do not ignore non-moving fingers
This commit allows the ZT7548 touchscreen driver to report fingers even when
they haven't moved since the last interrupt. It does this by adding
SUB_BIT_EXIST to the valid status bits and relaxing the sub_status check in
the interrupt handler to allow any non-zero sub_status.
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 3421b8ffb19b2..a0a89d25e25bb 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -406,7 +406,7 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
> u16 x, y;
>
> if (unlikely(!(p->sub_status &
> - (SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
> + (SUB_BIT_EXIST | SUB_BIT_UP | SUB_BIT_DOWN | SUB_BIT_MOVE)))) {
[Severity: High]
Does this modification allow a contact with SUB_BIT_MOVE, SUB_BIT_UP, or
SUB_BIT_DOWN to bypass validation and report coordinates even if the mandatory
SUB_BIT_EXIST valid bit is missing?
If the hardware clears the SUB_BIT_EXIST flag for a removed finger but leaves
stale status bits (like SUB_BIT_MOVE) in the I2C memory buffer, will this
cause stale slots to be processed as ghost touches?
> dev_dbg(&bt541->client->dev, "unknown finger event %#02x\n",
> p->sub_status);
> return;
[ ... ]
> @@ -473,7 +473,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
> const struct point_coord *p = &touch_event.point_coord[i];
>
> /* Only process contacts that are actually reported */
> - if (p->sub_status & SUB_BIT_EXIST)
> + if (p->sub_status)
[Severity: High]
Will removing the strict SUB_BIT_EXIST check pass any slot with stale status
bits to the processing logic?
Since the driver now relies entirely on status bits to validate active slots,
a stale slot without SUB_BIT_EXIST but with a non-zero sub_status (like
SUB_BIT_MOVE) will now pass both checks.
> zinitix_report_finger(bt541, i, p);
> }
[Severity: High]
This is a pre-existing issue, but does the driver register the input device
before fully initializing its private data?
In drivers/input/touchscreen/zinitix.c:zinitix_ts_probe():
error = zinitix_init_input_dev(bt541);
if (error) {
...
}
error = device_property_read_u32(&client->dev, "zinitix,mode",
&bt541->zinitix_mode);
If the kernel's kbd_handler synchronously opens the device during registration
(due to EV_KEY), zinitix_init_touch() will configure the hardware using the
uninitialized zinitix_mode (0) instead of the parsed mode. Does this lead to
malfunctioning touch reporting for devices declaring linux,keycodes in their
device tree?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-zinitix-modes-v3-0-2c8de712997a@disroot.org?part=2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event
2026-07-30 20:18 ` [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
@ 2026-07-30 20:31 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-07-30 20:31 UTC (permalink / raw)
To: Kaustabh Chakraborty
Cc: dmitry.torokhov, linux-input, robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] Unconditionally iterating all slots without a mask reinstates a known phantom fingers bug on certain devices.
Pre-existing issues:
- [High] The input device is registered and exposed to userspace before its operational properties are fully parsed and initialized.
- [High] Failing to read icon events discards already successfully read touch events, bypassing synchronization.
- [High] Stack-allocated variables are used directly as data buffers for I2C transfers, violating DMA safety requirements.
--
--- Patch [1]: [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event ---
commit 324dca54b2be4e95e88ba6bec7c1bec867e0e687
Author: Kaustabh Chakraborty <kauschluss@disroot.org>
Input: zinitix - check all available fingers for every touch event
This patch changes the touch reporting to iterate unconditionally over all
slots rather than relying on the finger_mask field. It relies on the
SUB_BIT_EXIST bit in the finger status to filter valid touches.
Link: https://android.googlesource.com/kernel/bcm/+/23d376ef33aa4c500a5ea24a290f029d5f8e2de3/drivers/input/touchscreen/zinitix_touch.c#1942 [1]
> diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
> index 0c36765bd79f8..3421b8ffb19b2 100644
> --- a/drivers/input/touchscreen/zinitix.c
> +++ b/drivers/input/touchscreen/zinitix.c
> @@ -445,7 +445,6 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
> struct bt541_ts_data *bt541 = bt541_handler;
> struct i2c_client *client = bt541->client;
> struct touch_event touch_event;
[Severity: High]
This isn't a bug introduced by this patch, but touch_event is allocated on
the stack and then passed to zinitix_read_data(), which feeds it directly
to the I2C subsystem. Since this buffer might be used for DMA transfers on
certain I2C host controllers, can this cause memory corruption or a kernel
panic when CONFIG_VMAP_STACK is enabled?
Similarly, in zinitix_read_data():
zinitix_read_data() {
__le16 reg_le = cpu_to_le16(reg);
...
ret = i2c_master_send(client, (u8 *)®_le, sizeof(reg_le));
...
}
Are there similar DMA safety concerns when using the stack-allocated reg_le
buffer for I2C sending?
> - unsigned long finger_mask;
> __le16 icon_events;
> int error;
> int i;
> @@ -470,8 +469,7 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
> zinitix_report_keys(bt541, le16_to_cpu(icon_events));
> }
[Severity: High]
This is a pre-existing issue, but I noticed something about the error handling
just above this block:
zinitix_ts_irq_handler() {
...
if (le16_to_cpu(touch_event.status) & BIT_ICON_EVENT) {
error = zinitix_read_data(bt541->client, bt541->icon_status_reg,
&icon_events, sizeof(icon_events));
if (error) {
dev_err(&client->dev, "Failed to read icon events\n");
goto out;
}
...
}
...
out:
zinitix_write_cmd(bt541->client, ZINITIX_CLEAR_INT_STATUS_CMD);
return IRQ_HANDLED;
}
If zinitix_read_data() for the icon events fails, the code jumps directly to
out. Will this discard the successfully read touch_event data and skip the
input_mt_sync_frame() and input_sync() calls, potentially leaving stuck touches
in the input core?
>
> - finger_mask = touch_event.finger_mask;
> - for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
> + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) {
> const struct point_coord *p = &touch_event.point_coord[i];
>
> /* Only process contacts that are actually reported */
[Severity: High]
The commit message mentions that phantom fingers will be ignored because
zinitix_report_finger() checks the SUB_BIT_EXIST bit. However, the
finger_mask check was originally introduced (in commit e941dc13fd37) because
some hardware erroneously sets SUB_BIT_EXIST for phantom fingers.
By removing the finger_mask iteration, is it possible this reinstates the
known phantom touches bug on affected hardware (like the BT404) where a
single physical touch causes multiple active slots?
[Severity: High]
This isn't a bug introduced by this patch, but looking at the device
initialization in zinitix_ts_probe():
zinitix_ts_probe() {
...
error = zinitix_init_input_dev(bt541);
if (error) {
...
}
error = device_property_read_u32(&client->dev, "zinitix,mode",
&bt541->zinitix_mode);
...
}
Since zinitix_init_input_dev() calls input_register_device(), the input
device becomes immediately visible to userspace. If userspace opens the device
instantly, zinitix_input_open() -> zinitix_start() will run before the
zinitix,mode property is read.
Could this cause the hardware to be configured with an incorrect mode
(0 instead of the requested or default 2)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260731-zinitix-modes-v3-0-2c8de712997a@disroot.org?part=1
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-07-30 20:32 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 20:18 [PATCH v3 0/5] Support zinitix touch modes 0 and 1, dt changes to Galaxy J6 (j6lte) Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 1/5] Input: zinitix - check all available fingers for every touch event Kaustabh Chakraborty
2026-07-30 20:31 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 2/5] Input: zinitix - do not ignore non-moving fingers Kaustabh Chakraborty
2026-07-30 20:31 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 3/5] Input: zinitix - add support for modes 0 and 1 Kaustabh Chakraborty
2026-07-30 20:29 ` sashiko-bot
2026-07-30 20:18 ` [PATCH v3 4/5] dt-bindings: input/ts/zinitix: document mode 0 Kaustabh Chakraborty
2026-07-30 20:18 ` [PATCH v3 5/5] arm64: dts: exynos7870-j6lte: set mode 0 as default for zinitix touchscreen Kaustabh Chakraborty
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox