Devicetree
 help / color / mirror / Atom feed
From: "Michał Kopeć" <michal@nozomi.space>
To: linux-input@vger.kernel.org
Cc: devicetree@vger.kernel.org, linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, "Jiri Kosina" <jikos@kernel.org>,
	"Benjamin Tissoires" <bentiss@kernel.org>,
	"Dmitry Torokhov" <dmitry.torokhov@gmail.com>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Matthias Brugger" <matthias.bgg@gmail.com>,
	"AngeloGioacchino Del Regno"
	<angelogioacchino.delregno@collabora.com>,
	"Allen Lin" <allencl_lin@hotmail.com>,
	"Tylor Yang" <tylor_yang@himax.corp-partner.google.com>,
	"Felix Kaechele" <felix@kaechele.ca>,
	"Douglas Anderson" <dianders@chromium.org>,
	"Michał Kopeć" <michal@nozomi.space>
Subject: [PATCH v5 5/6] HID: himax: Report the touch and heatmap data
Date: Sat,  3 Oct 2026 16:27:40 +0200	[thread overview]
Message-ID: <20261003142741.48634-6-michal@nozomi.space> (raw)
In-Reply-To: <20261003142741.48634-1-michal@nozomi.space>

With the HX83102J firmware on Ciri, every interrupt delivers a frame
with the touch report, the stylus report and a heatmap. The driver only
passed the stylus report to HID core, so touches were never reported.
The firmware report descriptor also declares the heatmap as input
report 97, and hid-multitouch rejected the frames that did not carry it
in full, after which the driver reset the controller over and over.

Report the touch report as well, and size the transfer buffer for the
heatmap that follows the stylus report. The IC packs the heatmap as
12-bit values, while report 97 declares 16-bit ones, so unpack it into
a separate buffer before reporting it.

The heatmap handling is based on Tylor Yang's change to the ChromeOS
kernel driver.

Link: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/5326106
Co-developed-by: Tylor Yang <tylor_yang@himax.corp-partner.google.com>
Signed-off-by: Tylor Yang <tylor_yang@himax.corp-partner.google.com>
Signed-off-by: Michał Kopeć <michal@nozomi.space>
---
 drivers/hid/hid-himax.c | 51 +++++++++++++++++++++++++++++++++++++++++
 drivers/hid/hid-himax.h |  6 +++++
 2 files changed, 57 insertions(+)

diff --git a/drivers/hid/hid-himax.c b/drivers/hid/hid-himax.c
index 533d7be629147..40abae724743d 100644
--- a/drivers/hid/hid-himax.c
+++ b/drivers/hid/hid-himax.c
@@ -2150,6 +2150,37 @@ static void himax_hid_remove(struct himax_ts_data *ts)
 	ts->hid = NULL;
 }
 
+/**
+ * himax_decompress_heatmap() - Unpack the heatmap into its HID report
+ * @ts: Himax touch screen data
+ * @src: Heatmap as read from the event stack
+ *
+ * The IC packs two 12-bit heatmap values into three bytes, while the HID
+ * report descriptor of the firmware declares 16-bit values. Copy the report
+ * ID and heatmap info header, then widen every pair of values to the
+ * little-endian 16-bit layout of the report.
+ *
+ * Return: None
+ */
+static void himax_decompress_heatmap(struct himax_ts_data *ts, const u8 *src)
+{
+	u32 i;
+	u32 count = ts->ic_data.rx_num * ts->ic_data.tx_num;
+	const u32 header_size = HIMAX_HEAT_MAP_INFO_SZ + 1;
+	u8 *dst = ts->heatmap_buf;
+
+	memcpy(dst, src, header_size);
+	for (i = 0; i < count; i += 2) {
+		const u8 *packed = src + header_size + i * 3 / 2;
+		u8 *unpacked = dst + header_size + i * 2;
+
+		unpacked[0] = packed[0];
+		unpacked[1] = packed[2] >> 4;
+		unpacked[2] = packed[1];
+		unpacked[3] = packed[2] & 0x0f;
+	}
+}
+
 /**
  * himax_ts_operation() - Process the touch interrupt data
  * @ts: Himax touch screen data
@@ -2175,6 +2206,10 @@ static int himax_ts_operation(struct himax_ts_data *ts)
 	if (ret == HIMAX_TS_GET_DATA_FAIL)
 		return ret;
 	if (ts->hid_probed) {
+		ret = himax_hid_report(ts,
+				       ts->xfer_buf + HIMAX_HID_REPORT_HDR_SZ,
+				       ts->hid_desc.max_input_length -
+				       HIMAX_HID_REPORT_HDR_SZ);
 		offset = ts->hid_desc.max_input_length;
 		if (ts->ic_data.stylus_function) {
 			ret += himax_hid_report(ts,
@@ -2183,6 +2218,11 @@ static int himax_ts_operation(struct himax_ts_data *ts)
 						HIMAX_HID_REPORT_HDR_SZ);
 			offset += ts->hid_desc.max_input_length;
 		}
+		himax_decompress_heatmap(ts,
+					 ts->xfer_buf + offset + HIMAX_HID_REPORT_HDR_SZ);
+		ret += himax_hid_report(ts, ts->heatmap_buf,
+					(ts->ic_data.rx_num * ts->ic_data.tx_num * 2) +
+					HIMAX_HEAT_MAP_INFO_SZ + 1);
 	}
 
 	if (ret != 0)
@@ -2322,6 +2362,9 @@ static int himax_hid_report_data_init(struct himax_ts_data *ts)
 	ts->touch_data_sz = ts->hid_desc.max_input_length;
 	if (ts->ic_data.stylus_function)
 		ts->touch_data_sz += ts->hid_desc.max_input_length;
+	ts->heatmap_data_size = ts->ic_data.rx_num * ts->ic_data.tx_num * 3 / 2;
+	ts->touch_data_sz += HIMAX_HEAT_MAP_HEADER_SZ +
+			     HIMAX_HEAT_MAP_INFO_SZ + ts->heatmap_data_size;
 	if (ts->touch_data_sz != ts->xfer_buf_sz) {
 		kfree(ts->xfer_buf);
 		ts->xfer_buf_sz = 0;
@@ -2331,6 +2374,14 @@ static int himax_hid_report_data_init(struct himax_ts_data *ts)
 		ts->xfer_buf_sz = ts->touch_data_sz;
 	}
 
+	if (!ts->heatmap_buf) {
+		ts->heatmap_buf = devm_kzalloc(ts->dev,
+					       ts->ic_data.rx_num * ts->ic_data.tx_num * 2 +
+					       HIMAX_HEAT_MAP_INFO_SZ + 1, GFP_KERNEL);
+		if (!ts->heatmap_buf)
+			return -ENOMEM;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/hid/hid-himax.h b/drivers/hid/hid-himax.h
index 71599520b8006..3582f8e00ef1b 100644
--- a/drivers/hid/hid-himax.h
+++ b/drivers/hid/hid-himax.h
@@ -52,6 +52,8 @@
 #define HIMAX_ZF_PARTITION_DESC_SZ			16U
 /* HIDRAW report header size */
 #define HIMAX_HID_REPORT_HDR_SZ				2U
+#define HIMAX_HEAT_MAP_HEADER_SZ			3U
+#define HIMAX_HEAT_MAP_INFO_SZ				20U
 /* hx83102j IC parameters */
 #define HIMAX_HX83102J_DSRAM_SZ				73728U
 #define HIMAX_HX83102J_FLASH_SIZE			261120U
@@ -392,11 +394,13 @@ struct himax_platform_data {
  * @xfer_buf: Interrupt data buffer
  * @xfer_rx_data: SPI Transfer receive data buffer
  * @xfer_tx_data: SPI Transfer transmit data buffer
+ * @heatmap_buf: Decompressed heatmap HID report
  * @zf_update_cfg_buffer: Zero flash update configuration buffer
  * @himax_irq: IRQ number
  * @chip_max_dsram_size: Maximum size of DSRAM
  * @spi_xfer_max_sz: Size of SPI controller max transfer size
  * @xfer_buf_sz: Size of interrupt data buffer
+ * @heatmap_data_size: Packed heatmap data size
  * @irq_state: IRQ state
  * @irq_lock: Spin lock for irq
  * @initialized: Indicate the driver is initialized
@@ -424,11 +428,13 @@ struct himax_ts_data {
 	u8 *xfer_buf;
 	u8 *xfer_rx_data;
 	u8 *xfer_tx_data;
+	u8 *heatmap_buf;
 	u8 *zf_update_cfg_buffer;
 	s32 himax_irq;
 	u32 chip_max_dsram_size;
 	u32 spi_xfer_max_sz;
 	u32 xfer_buf_sz;
+	u32 heatmap_data_size;
 	atomic_t irq_state;
 	/* lock for irq_save */
 	spinlock_t irq_lock;
-- 
2.55.0


  parent reply	other threads:[~2026-10-03 14:27 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-03 14:27 [PATCH v5 0/6] HID: Add support for the Himax HX83102J touchscreen Michał Kopeć
2026-10-03 14:27 ` [PATCH v5 1/6] dt-bindings: input: Add " Michał Kopeć
2026-10-03 17:56   ` sashiko-bot
2026-10-04  7:45   ` Krzysztof Kozlowski
2026-10-03 14:27 ` [PATCH v5 2/6] HID: Add Himax HX83102J touchscreen driver Michał Kopeć
2026-10-03 17:56   ` sashiko-bot
2026-10-04  7:50   ` Krzysztof Kozlowski
2026-10-03 14:27 ` [PATCH v5 3/6] HID: himax: Add DRM panel follower support Michał Kopeć
2026-10-03 17:56   ` sashiko-bot
2026-10-04  7:52   ` Krzysztof Kozlowski
2026-10-03 14:27 ` [PATCH v5 4/6] HID: himax: Load the firmware from a file Michał Kopeć
2026-10-03 17:56   ` sashiko-bot
2026-10-03 14:27 ` Michał Kopeć [this message]
2026-10-03 17:56   ` [PATCH v5 5/6] HID: himax: Report the touch and heatmap data sashiko-bot
2026-10-03 14:27 ` [PATCH v5 6/6] arm64: dts: mediatek: mt8188-geralt-ciri: Add the touchscreen Michał Kopeć

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261003142741.48634-6-michal@nozomi.space \
    --to=michal@nozomi.space \
    --cc=allencl_lin@hotmail.com \
    --cc=angelogioacchino.delregno@collabora.com \
    --cc=bentiss@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dianders@chromium.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=felix@kaechele.ca \
    --cc=jikos@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=matthias.bgg@gmail.com \
    --cc=robh@kernel.org \
    --cc=tylor_yang@himax.corp-partner.google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox