Przeglądaj źródła

Update v6.8 patches

Changes:
 - Fixed IPTS not compiling with -Werror enabled (@jasisonee)
 - Added QuickSPI support to ITHC for Surface Laptop Studio 2 (@quo)

Links:
 - kernel: https://github.com/linux-surface/kernel/commit/63781a056a0f06d5cc38d7755e0753c7ec08c51c
Dorian Stoll 1 rok temu
rodzic
commit
03cfcbc7c2

+ 53 - 0
patches/6.8/0004-ipts.patch

@@ -3236,3 +3236,56 @@ index 000000000000..1f966b8b32c4
 -- 
 2.44.0
 
+From e5b4ea8a015bee22023bb5c8fb6dd8b708bff7d5 Mon Sep 17 00:00:00 2001
+From: Jasmin Huber <jasmin@jasisonee.ch>
+Date: Mon, 15 Apr 2024 10:22:55 +0200
+Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile
+ with -Wmissing-prototypes.
+
+Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
+Patchset: ipts
+---
+ drivers/hid/ipts/eds1.c     | 1 +
+ drivers/hid/ipts/eds2.c     | 1 +
+ drivers/hid/ipts/receiver.c | 1 +
+ 3 files changed, 3 insertions(+)
+
+diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c
+index ecbb3a8bdaf6..7b9f54388a9f 100644
+--- a/drivers/hid/ipts/eds1.c
++++ b/drivers/hid/ipts/eds1.c
+@@ -14,6 +14,7 @@
+ #include "context.h"
+ #include "control.h"
+ #include "desc.h"
++#include "eds1.h"
+ #include "spec-device.h"
+ 
+ int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
+diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c
+index 198dc65d7887..639940794615 100644
+--- a/drivers/hid/ipts/eds2.c
++++ b/drivers/hid/ipts/eds2.c
+@@ -15,6 +15,7 @@
+ #include "context.h"
+ #include "control.h"
+ #include "desc.h"
++#include "eds2.h"
+ #include "spec-data.h"
+ 
+ int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
+diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c
+index ef66c3c9db80..977724c728c3 100644
+--- a/drivers/hid/ipts/receiver.c
++++ b/drivers/hid/ipts/receiver.c
+@@ -16,6 +16,7 @@
+ #include "context.h"
+ #include "control.h"
+ #include "hid.h"
++#include "receiver.h"
+ #include "resources.h"
+ #include "spec-device.h"
+ #include "thread.h"
+-- 
+2.44.0
+

+ 2520 - 0
patches/6.8/0005-ithc.patch

@@ -1818,3 +1818,2523 @@ index 000000000000..028e55a4ec53
 -- 
 2.44.0
 
+From 62697b8742afc950b55ed24d8ef2fca5834426b6 Mon Sep 17 00:00:00 2001
+From: quo <tuple@list.ru>
+Date: Fri, 19 Apr 2024 22:11:09 +0200
+Subject: [PATCH] hid: ithc: Update from quo/ithc-linux
+
+ - Added QuickSPI support for Surface Laptop Studio 2
+ - Use Latency Tolerance Reporting instead of manual CPU latency adjustments
+
+Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31
+
+Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
+Patchset: ithc
+---
+ drivers/hid/ithc/Kbuild          |   2 +-
+ drivers/hid/ithc/ithc-debug.c    |  33 +-
+ drivers/hid/ithc/ithc-debug.h    |   7 +
+ drivers/hid/ithc/ithc-dma.c      | 125 ++-----
+ drivers/hid/ithc/ithc-dma.h      |  24 +-
+ drivers/hid/ithc/ithc-hid.c      | 207 +++++++++++
+ drivers/hid/ithc/ithc-hid.h      |  32 ++
+ drivers/hid/ithc/ithc-legacy.c   | 252 ++++++++++++++
+ drivers/hid/ithc/ithc-legacy.h   |   8 +
+ drivers/hid/ithc/ithc-main.c     | 386 ++++-----------------
+ drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++
+ drivers/hid/ithc/ithc-quickspi.h |  39 +++
+ drivers/hid/ithc/ithc-regs.c     |  72 +++-
+ drivers/hid/ithc/ithc-regs.h     | 143 ++++----
+ drivers/hid/ithc/ithc.h          |  71 ++--
+ 15 files changed, 1441 insertions(+), 538 deletions(-)
+ create mode 100644 drivers/hid/ithc/ithc-debug.h
+ create mode 100644 drivers/hid/ithc/ithc-hid.c
+ create mode 100644 drivers/hid/ithc/ithc-hid.h
+ create mode 100644 drivers/hid/ithc/ithc-legacy.c
+ create mode 100644 drivers/hid/ithc/ithc-legacy.h
+ create mode 100644 drivers/hid/ithc/ithc-quickspi.c
+ create mode 100644 drivers/hid/ithc/ithc-quickspi.h
+
+diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild
+index aea83f2ac07b..4937ba131297 100644
+--- a/drivers/hid/ithc/Kbuild
++++ b/drivers/hid/ithc/Kbuild
+@@ -1,6 +1,6 @@
+ obj-$(CONFIG_HID_ITHC) := ithc.o
+ 
+-ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o
++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o
+ 
+ ccflags-y := -std=gnu11 -Wno-declaration-after-statement
+ 
+diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c
+index 1f1f1e33f2e5..2d8c6afe9966 100644
+--- a/drivers/hid/ithc/ithc-debug.c
++++ b/drivers/hid/ithc/ithc-debug.c
+@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si
+ 	case 'd': // dma command: cmd len data...
+ 		// get report descriptor: d 7 8 0 0
+ 		// enable multitouch: d 3 2 0x0105
+-		if (n < 2 || a[1] > (n - 2) * 4)
++		if (n < 1)
+ 			return -EINVAL;
+-		pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]);
+-		if (ithc_dma_tx(ithc, a[0], a[1], a + 2))
++		pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4);
++		struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a };
++		if (ithc_dma_tx(ithc, &data))
+ 			pci_err(ithc->pci, "dma tx failed\n");
+ 		break;
+ 	default:
+@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si
+ 	return len;
+ }
+ 
++static struct dentry *dbg_dir;
++
++void __init ithc_debug_init_module(void)
++{
++	struct dentry *d = debugfs_create_dir(DEVNAME, NULL);
++	if (IS_ERR(d))
++		pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d));
++	else
++		dbg_dir = d;
++}
++
++void __exit ithc_debug_exit_module(void)
++{
++	debugfs_remove_recursive(dbg_dir);
++	dbg_dir = NULL;
++}
++
+ static const struct file_operations ithc_debugfops_cmd = {
+ 	.owner = THIS_MODULE,
+ 	.write = ithc_debugfs_cmd_write,
+@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = {
+ static void ithc_debugfs_devres_release(struct device *dev, void *res)
+ {
+ 	struct dentry **dbgm = res;
+-	if (*dbgm)
+-		debugfs_remove_recursive(*dbgm);
++	debugfs_remove_recursive(*dbgm);
+ }
+ 
+-int ithc_debug_init(struct ithc *ithc)
++int ithc_debug_init_device(struct ithc *ithc)
+ {
++	if (!dbg_dir)
++		return -ENOENT;
+ 	struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL);
+ 	if (!dbgm)
+ 		return -ENOMEM;
+ 	devres_add(&ithc->pci->dev, dbgm);
+-	struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL);
++	struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir);
+ 	if (IS_ERR(dbg))
+ 		return PTR_ERR(dbg);
+ 	*dbgm = dbg;
+diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h
+new file mode 100644
+index 000000000000..38c53d916bdb
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-debug.h
+@@ -0,0 +1,7 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++void ithc_debug_init_module(void);
++void ithc_debug_exit_module(void);
++int ithc_debug_init_device(struct ithc *ithc);
++void ithc_log_regs(struct ithc *ithc);
++
+diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c
+index ffb8689b8a78..bf4eab33062b 100644
+--- a/drivers/hid/ithc/ithc-dma.c
++++ b/drivers/hid/ithc/ithc-dma.c
+@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel)
+ 	mutex_init(&rx->mutex);
+ 
+ 	// Allocate buffers.
+-	u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes);
+-	unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
++	unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ 	pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n",
+-		NUM_RX_BUF, buf_size, num_pages);
++		NUM_RX_BUF, ithc->max_rx_size, num_pages);
+ 	CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE);
+ 	for (unsigned int i = 0; i < NUM_RX_BUF; i++)
+ 		CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]);
+@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc)
+ 	mutex_init(&tx->mutex);
+ 
+ 	// Allocate buffers.
+-	tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes);
+-	unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE;
++	unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ 	pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n",
+-		tx->max_size, num_pages);
++		ithc->max_tx_size, num_pages);
+ 	CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE);
+ 	CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf);
+ 
+@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc)
+ 	return 0;
+ }
+ 
+-static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data,
+-	u8 channel, u8 buf)
+-{
+-	if (buf >= NUM_RX_BUF) {
+-		pci_err(ithc->pci, "invalid dma ringbuffer index\n");
+-		return -EINVAL;
+-	}
+-	u32 len = data->data_size;
+-	struct ithc_dma_rx_header *hdr = data->addr;
+-	u8 *hiddata = (void *)(hdr + 1);
+-	if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) {
+-		// The THC sends a reset request when we need to reinitialize the device.
+-		// This usually only happens if we send an invalid command or put the device
+-		// in a bad state.
+-		CHECK(ithc_reset, ithc);
+-	} else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) {
+-		if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
+-			// When the CPU enters a low power state during DMA, we can get truncated
+-			// messages. For Surface devices, this will typically be a single touch
+-			// report that is only 1 byte, or a multitouch report that is 257 bytes.
+-			// See also ithc_set_active().
+-		} else {
+-			pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n",
+-				channel, buf, len, hdr->code, hdr->data_size);
+-			print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
+-				hdr, min(len, 0x400u), 0);
+-		}
+-	} else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) {
+-		// Response to a 'get report descriptor' request.
+-		// The actual descriptor is preceded by 8 nul bytes.
+-		CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8);
+-		WRITE_ONCE(ithc->hid_parse_done, true);
+-		wake_up(&ithc->wait_hid_parse);
+-	} else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
+-		// Standard HID input report containing touch data.
+-		CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1);
+-	} else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) {
+-		// Response to a 'get feature' request.
+-		bool done = false;
+-		mutex_lock(&ithc->hid_get_feature_mutex);
+-		if (ithc->hid_get_feature_buf) {
+-			if (hdr->data_size < ithc->hid_get_feature_size)
+-				ithc->hid_get_feature_size = hdr->data_size;
+-			memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size);
+-			ithc->hid_get_feature_buf = NULL;
+-			done = true;
+-		}
+-		mutex_unlock(&ithc->hid_get_feature_mutex);
+-		if (done) {
+-			wake_up(&ithc->wait_hid_get_feature);
+-		} else {
+-			// Received data without a matching request, or the request already
+-			// timed out. (XXX What's the correct thing to do here?)
+-			CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT,
+-				hiddata, hdr->data_size, 1);
+-		}
+-	} else {
+-		pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n",
+-			channel, buf, len, hdr->code);
+-		print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
+-			hdr, min(len, 0x400u), 0);
+-	}
+-	return 0;
+-}
+-
+ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
+ {
+ 	// Process all filled RX buffers from the ringbuffer.
+@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
+ 		rx->num_received = ++n;
+ 
+ 		// process data
+-		CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail);
++		struct ithc_data d;
++		if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx)
++			(ithc, b->addr, b->data_size, &d) < 0) {
++			pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n",
++				channel, tail, b->data_size, min((int)b->data_size, 64), b->addr);
++			print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
++				b->addr, min(b->data_size, 0x400u), 0);
++		} else {
++			ithc_hid_process_data(ithc, &d);
++		}
+ 
+ 		// give the buffer back to the device
+ 		CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail);
+@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel)
+ 	return ret;
+ }
+ 
+-static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data)
+ {
+-	ithc_set_active(ithc, 100 * USEC_PER_MSEC);
+-
+ 	// Send a single TX buffer to the THC.
+-	pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize);
+-	struct ithc_dma_tx_header *hdr;
+-	// Data must be padded to next 4-byte boundary.
+-	u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0;
+-	unsigned int fullsize = sizeof(*hdr) + datasize + padding;
+-	if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE)
+-		return -EINVAL;
++	pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size);
+ 	CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
+ 
+ 	// Fill the TX buffer with header and data.
+-	ithc->dma_tx.buf.data_size = fullsize;
+-	hdr = ithc->dma_tx.buf.addr;
+-	hdr->code = cmdcode;
+-	hdr->data_size = datasize;
+-	u8 *dest = (void *)(hdr + 1);
+-	memcpy(dest, data, datasize);
+-	dest += datasize;
+-	for (u8 p = 0; p < padding; p++)
+-		*dest++ = 0;
++	ssize_t sz;
++	if (data->type == ITHC_DATA_RAW) {
++		sz = min(data->size, ithc->max_tx_size);
++		memcpy(ithc->dma_tx.buf.addr, data->data, sz);
++	} else {
++		sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx)
++			(ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size);
++	}
++	ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz;
+ 	CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
++	if (sz < 0) {
++		pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n",
++			data->type, data->size, (int)sz);
++		return -EINVAL;
++	}
+ 
+ 	// Let the THC process the buffer.
+ 	bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND);
+@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo
+ 	writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status);
+ 	return 0;
+ }
+-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data)
+ {
+ 	mutex_lock(&ithc->dma_tx.mutex);
+-	int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data);
++	int ret = ithc_dma_tx_unlocked(ithc, data);
+ 	mutex_unlock(&ithc->dma_tx.mutex);
+ 	return ret;
+ }
+diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h
+index 93652e4476bf..1749a5819b3e 100644
+--- a/drivers/hid/ithc/ithc-dma.h
++++ b/drivers/hid/ithc/ithc-dma.h
+@@ -11,27 +11,6 @@ struct ithc_phys_region_desc {
+ 	u32 unused;
+ };
+ 
+-#define DMA_RX_CODE_INPUT_REPORT          3
+-#define DMA_RX_CODE_FEATURE_REPORT        4
+-#define DMA_RX_CODE_REPORT_DESCRIPTOR     5
+-#define DMA_RX_CODE_RESET                 7
+-
+-struct ithc_dma_rx_header {
+-	u32 code;
+-	u32 data_size;
+-	u32 _unknown[14];
+-};
+-
+-#define DMA_TX_CODE_SET_FEATURE           3
+-#define DMA_TX_CODE_GET_FEATURE           4
+-#define DMA_TX_CODE_OUTPUT_REPORT         5
+-#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7
+-
+-struct ithc_dma_tx_header {
+-	u32 code;
+-	u32 data_size;
+-};
+-
+ struct ithc_dma_prd_buffer {
+ 	void *addr;
+ 	dma_addr_t dma_addr;
+@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer {
+ 
+ struct ithc_dma_tx {
+ 	struct mutex mutex;
+-	u32 max_size;
+ 	struct ithc_dma_prd_buffer prds;
+ 	struct ithc_dma_data_buffer buf;
+ };
+@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel);
+ void ithc_dma_rx_enable(struct ithc *ithc, u8 channel);
+ int ithc_dma_tx_init(struct ithc *ithc);
+ int ithc_dma_rx(struct ithc *ithc, u8 channel);
+-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata);
++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data);
+ 
+diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c
+new file mode 100644
+index 000000000000..065646ab499e
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-hid.c
+@@ -0,0 +1,207 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++static int ithc_hid_start(struct hid_device *hdev) { return 0; }
++static void ithc_hid_stop(struct hid_device *hdev) { }
++static int ithc_hid_open(struct hid_device *hdev) { return 0; }
++static void ithc_hid_close(struct hid_device *hdev) { }
++
++static int ithc_hid_parse(struct hid_device *hdev)
++{
++	struct ithc *ithc = hdev->driver_data;
++	const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR };
++	WRITE_ONCE(ithc->hid.parse_done, false);
++	for (int retries = 0; ; retries++) {
++		ithc_log_regs(ithc);
++		CHECK_RET(ithc_dma_tx, ithc, &get_report_desc);
++		if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done),
++				msecs_to_jiffies(200))) {
++			ithc_log_regs(ithc);
++			return 0;
++		}
++		if (retries > 5) {
++			ithc_log_regs(ithc);
++			pci_err(ithc->pci, "failed to read report descriptor\n");
++			return -ETIMEDOUT;
++		}
++		pci_warn(ithc->pci, "failed to read report descriptor, retrying\n");
++	}
++}
++
++static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf,
++	size_t len, unsigned char rtype, int reqtype)
++{
++	struct ithc *ithc = hdev->driver_data;
++	if (!buf || !len)
++		return -EINVAL;
++
++	struct ithc_data d = { .size = len, .data = buf };
++	buf[0] = reportnum;
++
++	if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) {
++		d.type = ITHC_DATA_OUTPUT_REPORT;
++		CHECK_RET(ithc_dma_tx, ithc, &d);
++		return 0;
++	}
++
++	if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) {
++		d.type = ITHC_DATA_SET_FEATURE;
++		CHECK_RET(ithc_dma_tx, ithc, &d);
++		return 0;
++	}
++
++	if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) {
++		d.type = ITHC_DATA_GET_FEATURE;
++		d.data = &reportnum;
++		d.size = 1;
++
++		// Prepare for response.
++		mutex_lock(&ithc->hid.get_feature_mutex);
++		ithc->hid.get_feature_buf = buf;
++		ithc->hid.get_feature_size = len;
++		mutex_unlock(&ithc->hid.get_feature_mutex);
++
++		// Transmit 'get feature' request.
++		int r = CHECK(ithc_dma_tx, ithc, &d);
++		if (!r) {
++			r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature,
++				!ithc->hid.get_feature_buf, msecs_to_jiffies(1000));
++			if (!r)
++				r = -ETIMEDOUT;
++			else if (r < 0)
++				r = -EINTR;
++			else
++				r = 0;
++		}
++
++		// If everything went ok, the buffer has been filled with the response data.
++		// Return the response size.
++		mutex_lock(&ithc->hid.get_feature_mutex);
++		ithc->hid.get_feature_buf = NULL;
++		if (!r)
++			r = ithc->hid.get_feature_size;
++		mutex_unlock(&ithc->hid.get_feature_mutex);
++		return r;
++	}
++
++	pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n",
++		rtype, reqtype, reportnum);
++	return -EINVAL;
++}
++
++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to
++// cast away the const to avoid a compiler warning...
++#define NOCONST(x) ((void *)x)
++
++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d)
++{
++	WARN_ON(!ithc->hid.dev);
++	if (!ithc->hid.dev)
++		return;
++
++	switch (d->type) {
++
++	case ITHC_DATA_IGNORE:
++		return;
++
++	case ITHC_DATA_ERROR:
++		CHECK(ithc_reset, ithc);
++		return;
++
++	case ITHC_DATA_REPORT_DESCRIPTOR:
++		// Response to the report descriptor request sent by ithc_hid_parse().
++		CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size);
++		WRITE_ONCE(ithc->hid.parse_done, true);
++		wake_up(&ithc->hid.wait_parse);
++		return;
++
++	case ITHC_DATA_INPUT_REPORT:
++	{
++		// Standard HID input report.
++		int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1);
++		if (r < 0) {
++			pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n",
++				r, d->size, d->size ? *(u8 *)d->data : 0);
++			print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1,
++				d->data, min(d->size, 0x400u), 0);
++		}
++		return;
++	}
++
++	case ITHC_DATA_GET_FEATURE:
++	{
++		// Response to a 'get feature' request sent by ithc_hid_raw_request().
++		bool done = false;
++		mutex_lock(&ithc->hid.get_feature_mutex);
++		if (ithc->hid.get_feature_buf) {
++			if (d->size < ithc->hid.get_feature_size)
++				ithc->hid.get_feature_size = d->size;
++			memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size);
++			ithc->hid.get_feature_buf = NULL;
++			done = true;
++		}
++		mutex_unlock(&ithc->hid.get_feature_mutex);
++		if (done) {
++			wake_up(&ithc->hid.wait_get_feature);
++		} else {
++			// Received data without a matching request, or the request already
++			// timed out. (XXX What's the correct thing to do here?)
++			CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT,
++				NOCONST(d->data), d->size, 1);
++		}
++		return;
++	}
++
++	default:
++		pci_err(ithc->pci, "unhandled data type %i\n", d->type);
++		return;
++	}
++}
++
++static struct hid_ll_driver ithc_ll_driver = {
++	.start = ithc_hid_start,
++	.stop = ithc_hid_stop,
++	.open = ithc_hid_open,
++	.close = ithc_hid_close,
++	.parse = ithc_hid_parse,
++	.raw_request = ithc_hid_raw_request,
++};
++
++static void ithc_hid_devres_release(struct device *dev, void *res)
++{
++	struct hid_device **hidm = res;
++	if (*hidm)
++		hid_destroy_device(*hidm);
++}
++
++int ithc_hid_init(struct ithc *ithc)
++{
++	struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL);
++	if (!hidm)
++		return -ENOMEM;
++	devres_add(&ithc->pci->dev, hidm);
++	struct hid_device *hid = hid_allocate_device();
++	if (IS_ERR(hid))
++		return PTR_ERR(hid);
++	*hidm = hid;
++
++	strscpy(hid->name, DEVFULLNAME, sizeof(hid->name));
++	strscpy(hid->phys, ithc->phys, sizeof(hid->phys));
++	hid->ll_driver = &ithc_ll_driver;
++	hid->bus = BUS_PCI;
++	hid->vendor = ithc->vendor_id;
++	hid->product = ithc->product_id;
++	hid->version = 0x100;
++	hid->dev.parent = &ithc->pci->dev;
++	hid->driver_data = ithc;
++
++	ithc->hid.dev = hid;
++
++	init_waitqueue_head(&ithc->hid.wait_parse);
++	init_waitqueue_head(&ithc->hid.wait_get_feature);
++	mutex_init(&ithc->hid.get_feature_mutex);
++
++	return 0;
++}
++
+diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h
+new file mode 100644
+index 000000000000..599eb912c8c8
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-hid.h
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++enum ithc_data_type {
++	ITHC_DATA_IGNORE,
++	ITHC_DATA_RAW,
++	ITHC_DATA_ERROR,
++	ITHC_DATA_REPORT_DESCRIPTOR,
++	ITHC_DATA_INPUT_REPORT,
++	ITHC_DATA_OUTPUT_REPORT,
++	ITHC_DATA_GET_FEATURE,
++	ITHC_DATA_SET_FEATURE,
++};
++
++struct ithc_data {
++	enum ithc_data_type type;
++	u32 size;
++	const void *data;
++};
++
++struct ithc_hid {
++	struct hid_device *dev;
++	bool parse_done;
++	wait_queue_head_t wait_parse;
++	wait_queue_head_t wait_get_feature;
++	struct mutex get_feature_mutex;
++	void *get_feature_buf;
++	size_t get_feature_size;
++};
++
++int ithc_hid_init(struct ithc *ithc);
++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d);
++
+diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c
+new file mode 100644
+index 000000000000..5c1da11e3f1d
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-legacy.c
+@@ -0,0 +1,252 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++#define DEVCFG_DMA_RX_SIZE(x)          ((((x) & 0x3fff) + 1) << 6)
++#define DEVCFG_DMA_TX_SIZE(x)          (((((x) >> 14) & 0x3ff) + 1) << 6)
++
++#define DEVCFG_TOUCH_MASK              0x3f
++#define DEVCFG_TOUCH_ENABLE            BIT(0)
++#define DEVCFG_TOUCH_PROP_DATA_ENABLE  BIT(1)
++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2)
++#define DEVCFG_TOUCH_POWER_STATE(x)    (((x) & 7) << 3)
++#define DEVCFG_TOUCH_UNKNOWN_6         BIT(6)
++
++#define DEVCFG_DEVICE_ID_TIC           0x43495424 // "$TIC"
++
++#define DEVCFG_SPI_CLKDIV(x)           (((x) >> 1) & 7)
++#define DEVCFG_SPI_CLKDIV_8            BIT(4)
++#define DEVCFG_SPI_SUPPORTS_SINGLE     BIT(5)
++#define DEVCFG_SPI_SUPPORTS_DUAL       BIT(6)
++#define DEVCFG_SPI_SUPPORTS_QUAD       BIT(7)
++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f)
++#define DEVCFG_SPI_MIN_RESET_TIME(x)   (((x) >> 16) & 0xf)
++#define DEVCFG_SPI_NEEDS_HEARTBEAT     BIT(20) // TODO implement heartbeat
++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7)
++#define DEVCFG_SPI_UNKNOWN_25          BIT(25)
++#define DEVCFG_SPI_UNKNOWN_26          BIT(26)
++#define DEVCFG_SPI_UNKNOWN_27          BIT(27)
++#define DEVCFG_SPI_DELAY(x)            (((x) >> 28) & 7) // TODO use this
++#define DEVCFG_SPI_USE_EXT_READ_CFG    BIT(31) // TODO use this?
++
++struct ithc_device_config { // (Example values are from an SP7+.)
++	u32 irq_cause;        // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET)
++	u32 error;            // 04 = 0x00000000
++	u32 dma_buf_sizes;    // 08 = 0x000a00ff
++	u32 touch_cfg;        // 0c = 0x0000001c
++	u32 touch_state;      // 10 = 0x0000001c
++	u32 device_id;        // 14 = 0x43495424 = "$TIC"
++	u32 spi_config;       // 18 = 0xfda00a2e
++	u16 vendor_id;        // 1c = 0x045e = Microsoft Corp.
++	u16 product_id;       // 1e = 0x0c1a
++	u32 revision;         // 20 = 0x00000001
++	u32 fw_version;       // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices)
++	u32 command;          // 28 = 0x00000000
++	u32 fw_mode;          // 2c = 0x00000000 (for fw update?)
++	u32 _unknown_30;      // 30 = 0x00000000
++	u8 eds_minor_ver;     // 34 = 0x5e
++	u8 eds_major_ver;     // 35 = 0x03
++	u8 interface_rev;     // 36 = 0x04
++	u8 eu_kernel_ver;     // 37 = 0x04
++	u32 _unknown_38;      // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET)
++	u32 _unknown_3c;      // 3c = 0x00000002
++};
++static_assert(sizeof(struct ithc_device_config) == 64);
++
++#define RX_CODE_INPUT_REPORT          3
++#define RX_CODE_FEATURE_REPORT        4
++#define RX_CODE_REPORT_DESCRIPTOR     5
++#define RX_CODE_RESET                 7
++
++#define TX_CODE_SET_FEATURE           3
++#define TX_CODE_GET_FEATURE           4
++#define TX_CODE_OUTPUT_REPORT         5
++#define TX_CODE_GET_REPORT_DESCRIPTOR 7
++
++static int ithc_set_device_enabled(struct ithc *ithc, bool enable)
++{
++	u32 x = ithc->legacy_touch_cfg =
++		(ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) |
++		DEVCFG_TOUCH_HID_REPORT_ENABLE |
++		(enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0);
++	return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE,
++		offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x);
++}
++
++int ithc_legacy_init(struct ithc *ithc)
++{
++	// Since we don't yet know which SPI config the device wants, use default speed and mode
++	// initially for reading config data.
++	CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE);
++
++	// Setting the following bit seems to make reading the config more reliable.
++	bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31);
++
++	// Setting this bit may be necessary on some ADL devices.
++	switch (ithc->pci->device) {
++	case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1:
++	case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2:
++	case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1:
++	case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2:
++		bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5);
++		break;
++	}
++
++	// Take the touch device out of reset.
++	bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
++	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0);
++	for (int retries = 0; ; retries++) {
++		ithc_log_regs(ithc);
++		bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET);
++		if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2))
++			break;
++		if (retries > 5) {
++			pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n",
++				readl(&ithc->regs->irq_cause));
++			return -ETIMEDOUT;
++		}
++		pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n");
++		bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
++		if (msleep_interruptible(1000))
++			return -EINTR;
++	}
++	ithc_log_regs(ithc);
++
++	CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY);
++
++	// Read configuration data.
++	u32 spi_cfg;
++	for (int retries = 0; ; retries++) {
++		ithc_log_regs(ithc);
++		struct ithc_device_config config = { 0 };
++		CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config);
++		u32 *p = (void *)&config;
++		pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
++			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
++		if (config.device_id == DEVCFG_DEVICE_ID_TIC) {
++			spi_cfg = config.spi_config;
++			ithc->vendor_id = config.vendor_id;
++			ithc->product_id = config.product_id;
++			ithc->product_rev = config.revision;
++			ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes);
++			ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes);
++			ithc->legacy_touch_cfg = config.touch_cfg;
++			ithc->have_config = true;
++			break;
++		}
++		if (retries > 10) {
++			pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n",
++				config.device_id);
++			return -EIO;
++		}
++		pci_warn(ithc->pci, "failed to read config, retrying\n");
++		if (msleep_interruptible(100))
++			return -EINTR;
++	}
++	ithc_log_regs(ithc);
++
++	// Apply SPI config and enable touch device.
++	CHECK_RET(ithc_set_spi_config, ithc,
++		DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0,
++		spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD :
++		spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL :
++		SPI_MODE_SINGLE,
++		SPI_MODE_SINGLE);
++	CHECK_RET(ithc_set_device_enabled, ithc, true);
++	ithc_log_regs(ithc);
++	return 0;
++}
++
++void ithc_legacy_exit(struct ithc *ithc)
++{
++	CHECK(ithc_set_device_enabled, ithc, false);
++}
++
++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest)
++{
++	const struct {
++		u32 code;
++		u32 data_size;
++		u32 _unknown[14];
++	} *hdr = src;
++
++	if (len < sizeof(*hdr))
++		return -ENODATA;
++	// Note: RX data is not padded, even though TX data must be padded.
++	if (len != sizeof(*hdr) + hdr->data_size)
++		return -EMSGSIZE;
++
++	dest->data = hdr + 1;
++	dest->size = hdr->data_size;
++
++	switch (hdr->code) {
++	case RX_CODE_RESET:
++		// The THC sends a reset request when we need to reinitialize the device.
++		// This usually only happens if we send an invalid command or put the device
++		// in a bad state.
++		dest->type = ITHC_DATA_ERROR;
++		return 0;
++	case RX_CODE_REPORT_DESCRIPTOR:
++		// The descriptor is preceded by 8 nul bytes.
++		if (hdr->data_size < 8)
++			return -ENODATA;
++		dest->type = ITHC_DATA_REPORT_DESCRIPTOR;
++		dest->data = (char *)(hdr + 1) + 8;
++		dest->size = hdr->data_size - 8;
++		return 0;
++	case RX_CODE_INPUT_REPORT:
++		dest->type = ITHC_DATA_INPUT_REPORT;
++		return 0;
++	case RX_CODE_FEATURE_REPORT:
++		dest->type = ITHC_DATA_GET_FEATURE;
++		return 0;
++	default:
++		return -EINVAL;
++	}
++}
++
++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest,
++	size_t maxlen)
++{
++	struct {
++		u32 code;
++		u32 data_size;
++	} *hdr = dest;
++
++	size_t src_size = src->size;
++	const void *src_data = src->data;
++	const u64 get_report_desc_data = 0;
++	u32 code;
++
++	switch (src->type) {
++	case ITHC_DATA_SET_FEATURE:
++		code = TX_CODE_SET_FEATURE;
++		break;
++	case ITHC_DATA_GET_FEATURE:
++		code = TX_CODE_GET_FEATURE;
++		break;
++	case ITHC_DATA_OUTPUT_REPORT:
++		code = TX_CODE_OUTPUT_REPORT;
++		break;
++	case ITHC_DATA_REPORT_DESCRIPTOR:
++		code = TX_CODE_GET_REPORT_DESCRIPTOR;
++		src_size = sizeof(get_report_desc_data);
++		src_data = &get_report_desc_data;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	// Data must be padded to next 4-byte boundary.
++	size_t padded = round_up(src_size, 4);
++	if (sizeof(*hdr) + padded > maxlen)
++		return -EOVERFLOW;
++
++	// Fill the TX buffer with header and data.
++	hdr->code = code;
++	hdr->data_size = src_size;
++	memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0);
++
++	return sizeof(*hdr) + padded;
++}
++
+diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h
+new file mode 100644
+index 000000000000..28d692462072
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-legacy.h
+@@ -0,0 +1,8 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++int ithc_legacy_init(struct ithc *ithc);
++void ithc_legacy_exit(struct ithc *ithc);
++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest);
++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest,
++	size_t maxlen);
++
+diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c
+index 87ed4aa70fda..2acf02e41d40 100644
+--- a/drivers/hid/ithc/ithc-main.c
++++ b/drivers/hid/ithc/ithc-main.c
+@@ -5,28 +5,6 @@
+ MODULE_DESCRIPTION("Intel Touch Host Controller driver");
+ MODULE_LICENSE("Dual BSD/GPL");
+ 
+-// Lakefield
+-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1    0x98d0
+-#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2    0x98d1
+-// Tiger Lake
+-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0
+-#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1
+-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1  0x43d0
+-#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2  0x43d1
+-// Alder Lake
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1  0x7ad8
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2  0x7ad9
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1  0x51d0
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2  0x51d1
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1  0x54d0
+-#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2  0x54d1
+-// Raptor Lake
+-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1  0x7a58
+-#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2  0x7a59
+-// Meteor Lake
+-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1    0x7e48
+-#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2    0x7e4a
+-
+ static const struct pci_device_id ithc_pci_tbl[] = {
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) },
+ 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) },
+@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true;
+ module_param_named(rx1, ithc_use_rx1, bool, 0);
+ MODULE_PARM_DESC(rx1, "Use DMA RX channel 1");
+ 
+-// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering.
+-static int ithc_dma_latency_us = 200;
+-module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0);
+-MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS");
++static int ithc_active_ltr_us = -1;
++module_param_named(activeltr, ithc_active_ltr_us, int, 0);
++MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)");
+ 
+-// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering.
+-static unsigned int ithc_dma_early_us = 2000;
+-module_param_named(dma_early_us, ithc_dma_early_us, uint, 0);
+-MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)");
++static int ithc_idle_ltr_us = -1;
++module_param_named(idleltr, ithc_idle_ltr_us, int, 0);
++MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)");
+ 
+ static bool ithc_log_regs_enabled = false;
+ module_param_named(logregs, ithc_log_regs_enabled, bool, 0);
+@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)");
+ 
+ // Sysfs attributes
+ 
+-static bool ithc_is_config_valid(struct ithc *ithc)
+-{
+-	return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC;
+-}
+-
+ static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ 	struct ithc *ithc = dev_get_drvdata(dev);
+-	if (!ithc || !ithc_is_config_valid(ithc))
++	if (!ithc || !ithc->have_config)
+ 		return -ENODEV;
+-	return sprintf(buf, "0x%04x", ithc->config.vendor_id);
++	return sprintf(buf, "0x%04x", ithc->vendor_id);
+ }
+ static DEVICE_ATTR_RO(vendor);
+ static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ 	struct ithc *ithc = dev_get_drvdata(dev);
+-	if (!ithc || !ithc_is_config_valid(ithc))
++	if (!ithc || !ithc->have_config)
+ 		return -ENODEV;
+-	return sprintf(buf, "0x%04x", ithc->config.product_id);
++	return sprintf(buf, "0x%04x", ithc->product_id);
+ }
+ static DEVICE_ATTR_RO(product);
+ static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ 	struct ithc *ithc = dev_get_drvdata(dev);
+-	if (!ithc || !ithc_is_config_valid(ithc))
++	if (!ithc || !ithc->have_config)
+ 		return -ENODEV;
+-	return sprintf(buf, "%u", ithc->config.revision);
++	return sprintf(buf, "%u", ithc->product_rev);
+ }
+ static DEVICE_ATTR_RO(revision);
+-static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf)
+-{
+-	struct ithc *ithc = dev_get_drvdata(dev);
+-	if (!ithc || !ithc_is_config_valid(ithc))
+-		return -ENODEV;
+-	u32 v = ithc->config.fw_version;
+-	return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff);
+-}
+-static DEVICE_ATTR_RO(fw_version);
+ 
+ static const struct attribute_group *ithc_attribute_groups[] = {
+ 	&(const struct attribute_group){
+@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = {
+ 			&dev_attr_vendor.attr,
+ 			&dev_attr_product.attr,
+ 			&dev_attr_revision.attr,
+-			&dev_attr_fw_version.attr,
+ 			NULL
+ 		},
+ 	},
+ 	NULL
+ };
+ 
+-// HID setup
+-
+-static int ithc_hid_start(struct hid_device *hdev) { return 0; }
+-static void ithc_hid_stop(struct hid_device *hdev) { }
+-static int ithc_hid_open(struct hid_device *hdev) { return 0; }
+-static void ithc_hid_close(struct hid_device *hdev) { }
+-
+-static int ithc_hid_parse(struct hid_device *hdev)
+-{
+-	struct ithc *ithc = hdev->driver_data;
+-	u64 val = 0;
+-	WRITE_ONCE(ithc->hid_parse_done, false);
+-	for (int retries = 0; ; retries++) {
+-		CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val);
+-		if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done),
+-				msecs_to_jiffies(200)))
+-			return 0;
+-		if (retries > 5) {
+-			pci_err(ithc->pci, "failed to read report descriptor\n");
+-			return -ETIMEDOUT;
+-		}
+-		pci_warn(ithc->pci, "failed to read report descriptor, retrying\n");
+-	}
+-}
+-
+-static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf,
+-	size_t len, unsigned char rtype, int reqtype)
+-{
+-	struct ithc *ithc = hdev->driver_data;
+-	if (!buf || !len)
+-		return -EINVAL;
+-	u32 code;
+-	if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) {
+-		code = DMA_TX_CODE_OUTPUT_REPORT;
+-	} else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) {
+-		code = DMA_TX_CODE_SET_FEATURE;
+-	} else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) {
+-		code = DMA_TX_CODE_GET_FEATURE;
+-	} else {
+-		pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n",
+-			rtype, reqtype, reportnum);
+-		return -EINVAL;
+-	}
+-	buf[0] = reportnum;
+-
+-	if (reqtype == HID_REQ_GET_REPORT) {
+-		// Prepare for response.
+-		mutex_lock(&ithc->hid_get_feature_mutex);
+-		ithc->hid_get_feature_buf = buf;
+-		ithc->hid_get_feature_size = len;
+-		mutex_unlock(&ithc->hid_get_feature_mutex);
+-
+-		// Transmit 'get feature' request.
+-		int r = CHECK(ithc_dma_tx, ithc, code, 1, buf);
+-		if (!r) {
+-			r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature,
+-				!ithc->hid_get_feature_buf, msecs_to_jiffies(1000));
+-			if (!r)
+-				r = -ETIMEDOUT;
+-			else if (r < 0)
+-				r = -EINTR;
+-			else
+-				r = 0;
+-		}
+-
+-		// If everything went ok, the buffer has been filled with the response data.
+-		// Return the response size.
+-		mutex_lock(&ithc->hid_get_feature_mutex);
+-		ithc->hid_get_feature_buf = NULL;
+-		if (!r)
+-			r = ithc->hid_get_feature_size;
+-		mutex_unlock(&ithc->hid_get_feature_mutex);
+-		return r;
+-	}
+-
+-	// 'Set feature', or 'output report'. These don't have a response.
+-	CHECK_RET(ithc_dma_tx, ithc, code, len, buf);
+-	return 0;
+-}
+-
+-static struct hid_ll_driver ithc_ll_driver = {
+-	.start = ithc_hid_start,
+-	.stop = ithc_hid_stop,
+-	.open = ithc_hid_open,
+-	.close = ithc_hid_close,
+-	.parse = ithc_hid_parse,
+-	.raw_request = ithc_hid_raw_request,
+-};
+-
+-static void ithc_hid_devres_release(struct device *dev, void *res)
+-{
+-	struct hid_device **hidm = res;
+-	if (*hidm)
+-		hid_destroy_device(*hidm);
+-}
+-
+-static int ithc_hid_init(struct ithc *ithc)
+-{
+-	struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL);
+-	if (!hidm)
+-		return -ENOMEM;
+-	devres_add(&ithc->pci->dev, hidm);
+-	struct hid_device *hid = hid_allocate_device();
+-	if (IS_ERR(hid))
+-		return PTR_ERR(hid);
+-	*hidm = hid;
+-
+-	strscpy(hid->name, DEVFULLNAME, sizeof(hid->name));
+-	strscpy(hid->phys, ithc->phys, sizeof(hid->phys));
+-	hid->ll_driver = &ithc_ll_driver;
+-	hid->bus = BUS_PCI;
+-	hid->vendor = ithc->config.vendor_id;
+-	hid->product = ithc->config.product_id;
+-	hid->version = 0x100;
+-	hid->dev.parent = &ithc->pci->dev;
+-	hid->driver_data = ithc;
+-
+-	ithc->hid = hid;
+-	return 0;
+-}
+-
+ // Interrupts/polling
+ 
+-static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t)
+-{
+-	struct ithc *ithc = container_of(t, struct ithc, activity_start_timer);
+-	ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC);
+-	return HRTIMER_NORESTART;
+-}
+-
+-static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t)
+-{
+-	struct ithc *ithc = container_of(t, struct ithc, activity_end_timer);
+-	cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+-	return HRTIMER_NORESTART;
+-}
+-
+-void ithc_set_active(struct ithc *ithc, unsigned int duration_us)
+-{
+-	if (ithc_dma_latency_us < 0)
+-		return;
+-	// When CPU usage is very low, the CPU can enter various low power states (C2-C10).
+-	// This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be
+-	// set when this happens. The amount of truncated messages can become very high, resulting
+-	// in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency
+-	// QoS request to prevent the CPU from entering low power states during touch interactions.
+-	cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us);
+-	hrtimer_start_range_ns(&ithc->activity_end_timer,
+-		ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL);
+-}
+-
+-static int ithc_set_device_enabled(struct ithc *ithc, bool enable)
+-{
+-	u32 x = ithc->config.touch_cfg =
+-		(ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 |
+-		(enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0);
+-	return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE,
+-		offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x);
+-}
+-
+ static void ithc_disable_interrupts(struct ithc *ithc)
+ {
+ 	writel(0, &ithc->regs->error_control);
+ 	bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0);
+-	bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
+-	bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
++	bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0);
++	bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0);
+ 	bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0);
+ }
+ 
+ static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel)
+ {
+-	writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA,
++	writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA,
+ 		&ithc->regs->dma_rx[channel].status);
+ }
+ 
+@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc)
+ {
+ 	ithc_log_regs(ithc);
+ 
++	// The THC automatically transitions from LTR idle to active at the start of a DMA transfer.
++	// It does not appear to automatically go back to idle, so we switch it back here, since
++	// the DMA transfer should be complete.
++	ithc_set_ltr_idle(ithc);
++
+ 	bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
+ 	bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
+ 
+-	// Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer
+-	ktime_t t = ktime_get();
+-	ktime_t dt = ktime_sub(t, ithc->last_rx_time);
+-	if (rx0 || rx1) {
+-		ithc->last_rx_time = t;
+-		if (dt > ms_to_ktime(100)) {
+-			ithc->cur_rx_seq_count = 0;
+-			ithc->cur_rx_seq_errors = 0;
+-		}
+-		ithc->cur_rx_seq_count++;
+-		if (!ithc_use_polling && ithc_dma_latency_us >= 0) {
+-			// Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below)
+-			cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+-			hrtimer_try_to_cancel(&ithc->activity_end_timer);
+-		}
+-	}
+-
+ 	// Read and clear error bits
+ 	u32 err = readl(&ithc->regs->error_flags);
+ 	if (err) {
+ 		writel(err, &ithc->regs->error_flags);
+ 		if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT)
+ 			pci_err(ithc->pci, "error flags: 0x%08x\n", err);
+-		if (err & ERROR_FLAG_DMA_RX_TIMEOUT) {
+-			// Only log an error if we see a significant number of these errors.
+-			ithc->cur_rx_seq_errors++;
+-			if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10)
+-				pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n",
+-					ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt));
+-		}
++		if (err & ERROR_FLAG_DMA_RX_TIMEOUT)
++			pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n");
+ 	}
+ 
+ 	// Process DMA rx
+@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc)
+ 			ithc_dma_rx(ithc, 1);
+ 	}
+ 
+-	// Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT
+-	if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) {
+-		ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us));
+-		hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS);
+-	}
+-
+ 	ithc_log_regs(ithc);
+ }
+ 
+@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg)
+ 		ithc_process(ithc);
+ 		// Decrease polling interval to 20ms if we received data, otherwise slowly
+ 		// increase it up to 200ms.
+-		if (n != ithc->dma_rx[1].num_received) {
+-			ithc_set_active(ithc, 100 * USEC_PER_MSEC);
+-			sleep = 20;
+-		} else {
+-			sleep = min(200u, sleep + (sleep >> 4) + 1);
+-		}
++		sleep = n != ithc->dma_rx[1].num_received ? 20
++			: min(200u, sleep + (sleep >> 4) + 1);
+ 		msleep_interruptible(sleep);
+ 	}
+ 	return 0;
+@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc)
+ 
+ static int ithc_init_device(struct ithc *ithc)
+ {
++	// Read ACPI config for QuickSPI mode
++	struct ithc_acpi_config cfg = { 0 };
++	CHECK_RET(ithc_read_acpi_config, ithc, &cfg);
++	if (!cfg.has_config)
++		pci_info(ithc->pci, "no ACPI config, using legacy mode\n");
++	else
++		ithc_print_acpi_config(ithc, &cfg);
++	ithc->use_quickspi = cfg.has_config;
++
++	// Shut down device
+ 	ithc_log_regs(ithc);
+ 	bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0;
+ 	ithc_disable(ithc);
+ 	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY);
+-
+-	// Since we don't yet know which SPI config the device wants, use default speed and mode
+-	// initially for reading config data.
+-	ithc_set_spi_config(ithc, 10, 0);
+-
+-	// Setting the following bit seems to make reading the config more reliable.
+-	bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000);
++	ithc_log_regs(ithc);
+ 
+ 	// If the device was previously enabled, wait a bit to make sure it's fully shut down.
+ 	if (was_enabled)
+ 		if (msleep_interruptible(100))
+ 			return -EINTR;
+ 
+-	// Take the touch device out of reset.
+-	bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
+-	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0);
+-	for (int retries = 0; ; retries++) {
+-		ithc_log_regs(ithc);
+-		bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET);
+-		if (!waitl(ithc, &ithc->regs->state, 0xf, 2))
+-			break;
+-		if (retries > 5) {
+-			pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state));
+-			return -ETIMEDOUT;
+-		}
+-		pci_warn(ithc->pci, "invalid state, retrying reset\n");
+-		bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
+-		if (msleep_interruptible(1000))
+-			return -EINTR;
+-	}
+-	ithc_log_regs(ithc);
++	// Set Latency Tolerance Reporting config. The device will automatically
++	// apply these values depending on whether it is active or idle.
++	// If active value is too high, DMA buffer data can become truncated.
++	// By default, we set the active LTR value to 100us, and idle to 100ms.
++	u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000
++		: cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10
++		: 100 * 1000;
++	u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000
++		: cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10
++		: 100 * 1000 * 1000;
++	ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns);
++
++	if (ithc->use_quickspi)
++		CHECK_RET(ithc_quickspi_init, ithc, &cfg);
++	else
++		CHECK_RET(ithc_legacy_init, ithc);
+ 
+-	// Waiting for the following status bit makes reading config much more reliable,
+-	// however the official driver does not seem to do this...
+-	CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4);
+-
+-	// Read configuration data.
+-	for (int retries = 0; ; retries++) {
+-		ithc_log_regs(ithc);
+-		memset(&ithc->config, 0, sizeof(ithc->config));
+-		CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config);
+-		u32 *p = (void *)&ithc->config;
+-		pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+-			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
+-		if (ithc_is_config_valid(ithc))
+-			break;
+-		if (retries > 10) {
+-			pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n",
+-				ithc->config.device_id);
+-			return -EIO;
+-		}
+-		pci_warn(ithc->pci, "failed to read config, retrying\n");
+-		if (msleep_interruptible(100))
+-			return -EINTR;
+-	}
+-	ithc_log_regs(ithc);
+-
+-	// Apply SPI config and enable touch device.
+-	CHECK_RET(ithc_set_spi_config, ithc,
+-		DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config),
+-		DEVCFG_SPI_MODE(ithc->config.spi_config));
+-	CHECK_RET(ithc_set_device_enabled, ithc, true);
+-	ithc_log_regs(ithc);
+ 	return 0;
+ }
+ 
+@@ -527,11 +274,11 @@ static void ithc_stop(void *res)
+ 		CHECK(kthread_stop, ithc->poll_thread);
+ 	if (ithc->irq >= 0)
+ 		disable_irq(ithc->irq);
+-	CHECK(ithc_set_device_enabled, ithc, false);
++	if (ithc->use_quickspi)
++		ithc_quickspi_exit(ithc);
++	else
++		ithc_legacy_exit(ithc);
+ 	ithc_disable(ithc);
+-	hrtimer_cancel(&ithc->activity_start_timer);
+-	hrtimer_cancel(&ithc->activity_end_timer);
+-	cpu_latency_qos_remove_request(&ithc->activity_qos);
+ 
+ 	// Clear DMA config.
+ 	for (unsigned int i = 0; i < 2; i++) {
+@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci)
+ 	ithc->irq = -1;
+ 	ithc->pci = pci;
+ 	snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci));
+-	init_waitqueue_head(&ithc->wait_hid_parse);
+-	init_waitqueue_head(&ithc->wait_hid_get_feature);
+-	mutex_init(&ithc->hid_get_feature_mutex);
+ 	pci_set_drvdata(pci, ithc);
+ 	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci);
+ 	if (ithc_log_regs_enabled)
+@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci)
+ 
+ 	// Initialize THC and touch device.
+ 	CHECK_RET(ithc_init_device, ithc);
++
++	// Initialize HID and DMA.
++	CHECK_RET(ithc_hid_init, ithc);
+ 	CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups);
+ 	if (ithc_use_rx0)
+ 		CHECK_RET(ithc_dma_rx_init, ithc, 0);
+@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci)
+ 		CHECK_RET(ithc_dma_rx_init, ithc, 1);
+ 	CHECK_RET(ithc_dma_tx_init, ithc);
+ 
+-	cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+-	hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+-	ithc->activity_start_timer.function = ithc_activity_start_timer_callback;
+-	hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+-	ithc->activity_end_timer.function = ithc_activity_end_timer_callback;
+-
+ 	// Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are
+ 	// disabled BEFORE the buffers are freed.
+ 	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc);
+ 
+-	CHECK_RET(ithc_hid_init, ithc);
+-
+ 	// Start polling/IRQ.
+ 	if (ithc_use_polling) {
+ 		pci_info(pci, "using polling instead of irq\n");
+@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci)
+ 
+ 	// hid_add_device() can only be called after irq/polling is started and DMA is enabled,
+ 	// because it calls ithc_hid_parse() which reads the report descriptor via DMA.
+-	CHECK_RET(hid_add_device, ithc->hid);
++	CHECK_RET(hid_add_device, ithc->hid.dev);
++
++	CHECK(ithc_debug_init_device, ithc);
+ 
+-	CHECK(ithc_debug_init, ithc);
++	ithc_set_ltr_idle(ithc);
+ 
+ 	pci_dbg(pci, "started\n");
+ 	return 0;
+@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = {
+ 		.thaw = ithc_thaw,
+ 		.restore = ithc_restore,
+ 	},
++	.driver.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ 	//.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway
+ };
+ 
+ static int __init ithc_init(void)
+ {
++	ithc_debug_init_module();
+ 	return pci_register_driver(&ithc_driver);
+ }
+ 
+ static void __exit ithc_exit(void)
+ {
+ 	pci_unregister_driver(&ithc_driver);
++	ithc_debug_exit_module();
+ }
+ 
+ module_init(ithc_init);
+diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c
+new file mode 100644
+index 000000000000..760e55ead078
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-quickspi.c
+@@ -0,0 +1,578 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++// Some public THC/QuickSPI documentation can be found in:
++// - Intel Firmware Support Package repo: https://github.com/intel/FSP
++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325
++
++#include "ithc.h"
++
++static const guid_t guid_hidspi =
++	GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab);
++static const guid_t guid_thc_quickspi =
++	GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe);
++static const guid_t guid_thc_ltr =
++	GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38);
++
++// TODO The HIDSPI spec says revision should be 3. Should we try both?
++#define DSM_REV 2
++
++struct hidspi_header {
++	u8 type;
++	u16 len;
++	u8 id;
++} __packed;
++static_assert(sizeof(struct hidspi_header) == 4);
++
++#define HIDSPI_INPUT_TYPE_DATA                        1
++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE              3
++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE            4
++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE        5
++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR           7
++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR           8
++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE        9
++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE      10
++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE   11
++
++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST  1
++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST  2
++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE                3
++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE                4
++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT              5
++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST       6
++#define HIDSPI_OUTPUT_TYPE_COMMAND                    7
++
++struct hidspi_device_descriptor {
++	u16 wDeviceDescLength;
++	u16 bcdVersion;
++	u16 wReportDescLength;
++	u16 wMaxInputLength;
++	u16 wMaxOutputLength;
++	u16 wMaxFragmentLength;
++	u16 wVendorID;
++	u16 wProductID;
++	u16 wVersionID;
++	u16 wFlags;
++	u32 dwReserved;
++};
++static_assert(sizeof(struct hidspi_device_descriptor) == 24);
++
++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest)
++{
++	acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev);
++	union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL);
++	if (!o)
++		return 0;
++	if (o->type != ACPI_TYPE_INTEGER) {
++		pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n",
++			guid, func, o->type);
++		ACPI_FREE(o);
++		return -1;
++	}
++	pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value);
++	*dest = (u32)o->integer.value;
++	ACPI_FREE(o);
++	return 1;
++}
++
++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest)
++{
++	acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev);
++	union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL);
++	if (!o)
++		return 0;
++	if (o->type != ACPI_TYPE_BUFFER) {
++		pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n",
++			guid, func, o->type);
++		ACPI_FREE(o);
++		return -1;
++	}
++	if (o->buffer.length != len) {
++		pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n",
++			guid, func, o->buffer.length, len);
++		ACPI_FREE(o);
++		return -1;
++	}
++	memcpy(dest, o->buffer.pointer, len);
++	pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]);
++	ACPI_FREE(o);
++	return 1;
++}
++
++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg)
++{
++	int r;
++	acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev);
++
++	cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0));
++	if (!cfg->has_config)
++		return 0;
++
++	// HIDSPI settings
++
++	r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address);
++	if (r < 0)
++		return r;
++	cfg->has_input_report_header_address = r > 0;
++	if (r > 0 && cfg->input_report_header_address > 0xffffff) {
++		pci_err(ithc->pci, "Invalid input report header address 0x%x\n",
++			cfg->input_report_header_address);
++		return -1;
++	}
++
++	r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address);
++	if (r < 0)
++		return r;
++	cfg->has_input_report_body_address = r > 0;
++	if (r > 0 && cfg->input_report_body_address > 0xffffff) {
++		pci_err(ithc->pci, "Invalid input report body address 0x%x\n",
++			cfg->input_report_body_address);
++		return -1;
++	}
++
++	r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address);
++	if (r < 0)
++		return r;
++	cfg->has_output_report_body_address = r > 0;
++	if (r > 0 && cfg->output_report_body_address > 0xffffff) {
++		pci_err(ithc->pci, "Invalid output report body address 0x%x\n",
++			cfg->output_report_body_address);
++		return -1;
++	}
++
++	r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode);
++	if (r < 0)
++		return r;
++	cfg->has_read_opcode = r > 0;
++
++	r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode);
++	if (r < 0)
++		return r;
++	cfg->has_write_opcode = r > 0;
++
++	u32 flags;
++	r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags);
++	if (r < 0)
++		return r;
++	cfg->has_read_mode = cfg->has_write_mode = r > 0;
++	if (r > 0) {
++		cfg->read_mode = (flags >> 14) & 3;
++		cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE;
++	}
++
++	// Quick SPI settings
++
++	r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency);
++	if (r < 0)
++		return r;
++	cfg->has_spi_frequency = r > 0;
++
++	r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size);
++	if (r < 0)
++		return r;
++	cfg->has_limit_packet_size = r > 0;
++
++	r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay);
++	if (r < 0)
++		return r;
++	cfg->has_tx_delay = r > 0;
++	if (r > 0)
++		cfg->tx_delay &= 0xffff;
++
++	// LTR settings
++
++	r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr);
++	if (r < 0)
++		return r;
++	cfg->has_active_ltr = r > 0;
++	if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) {
++		if (cfg->active_ltr != 0xffffffff)
++			pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n",
++				cfg->active_ltr);
++		cfg->active_ltr = 500;
++	}
++
++	r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr);
++	if (r < 0)
++		return r;
++	cfg->has_idle_ltr = r > 0;
++	if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) {
++		if (cfg->idle_ltr != 0xffffffff)
++			pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n",
++				cfg->idle_ltr);
++		cfg->idle_ltr = 500;
++		if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr)
++			cfg->idle_ltr = cfg->active_ltr;
++	}
++
++	return 0;
++}
++
++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg)
++{
++	if (!cfg->has_config) {
++		pci_info(ithc->pci, "No ACPI config");
++		return;
++	}
++
++	char input_report_header_address[16] = "-";
++	if (cfg->has_input_report_header_address)
++		sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address);
++	char input_report_body_address[16] = "-";
++	if (cfg->has_input_report_body_address)
++		sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address);
++	char output_report_body_address[16] = "-";
++	if (cfg->has_output_report_body_address)
++		sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address);
++	char read_opcode[16] = "-";
++	if (cfg->has_read_opcode)
++		sprintf(read_opcode, "0x%02x", cfg->read_opcode);
++	char write_opcode[16] = "-";
++	if (cfg->has_write_opcode)
++		sprintf(write_opcode, "0x%02x", cfg->write_opcode);
++	char read_mode[16] = "-";
++	if (cfg->has_read_mode)
++		sprintf(read_mode, "%i", cfg->read_mode);
++	char write_mode[16] = "-";
++	if (cfg->has_write_mode)
++		sprintf(write_mode, "%i", cfg->write_mode);
++	char spi_frequency[16] = "-";
++	if (cfg->has_spi_frequency)
++		sprintf(spi_frequency, "%u", cfg->spi_frequency);
++	char limit_packet_size[16] = "-";
++	if (cfg->has_limit_packet_size)
++		sprintf(limit_packet_size, "%u", cfg->limit_packet_size);
++	char tx_delay[16] = "-";
++	if (cfg->has_tx_delay)
++		sprintf(tx_delay, "%u", cfg->tx_delay);
++	char active_ltr[16] = "-";
++	if (cfg->has_active_ltr)
++		sprintf(active_ltr, "%u", cfg->active_ltr);
++	char idle_ltr[16] = "-";
++	if (cfg->has_idle_ltr)
++		sprintf(idle_ltr, "%u", cfg->idle_ltr);
++
++	pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n",
++		input_report_header_address, input_report_body_address, output_report_body_address,
++		read_opcode, write_opcode, read_mode, write_mode,
++		spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr);
++}
++
++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg)
++{
++	pci_dbg(ithc->pci, "initializing QuickSPI registers\n");
++
++	// SPI frequency and mode
++	if (!cfg->has_spi_frequency || !cfg->spi_frequency) {
++		pci_err(ithc->pci, "Missing SPI frequency in configuration\n");
++		return -EINVAL;
++	}
++	unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency);
++	bool clkdiv8 = clkdiv > 7;
++	if (clkdiv8)
++		clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u));
++	if (!clkdiv)
++		clkdiv = 1;
++	CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8,
++		cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE,
++		cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE);
++
++	// SPI addresses and opcodes
++	if (cfg->has_input_report_header_address)
++		writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr);
++	if (cfg->has_input_report_body_address)
++		writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr);
++	if (cfg->has_output_report_body_address)
++		writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr);
++
++	if (cfg->has_read_opcode) {
++		writeb(cfg->read_opcode, &ithc->regs->read_opcode);
++		writeb(cfg->read_opcode, &ithc->regs->read_opcode_single);
++		writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual);
++		writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad);
++	}
++	if (cfg->has_write_opcode) {
++		writeb(cfg->write_opcode, &ithc->regs->write_opcode);
++		writeb(cfg->write_opcode, &ithc->regs->write_opcode_single);
++		writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual);
++		writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad);
++	}
++	ithc_log_regs(ithc);
++
++	// The rest...
++	bitsl(&ithc->regs->quickspi_config1,
++		QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) |
++		QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff),
++		QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) |
++		QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2));
++
++	bitsl(&ithc->regs->quickspi_config2,
++		QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) |
++		QUICKSPI_CONFIG2_UNKNOWN_12(0xff),
++		QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) |
++		QUICKSPI_CONFIG2_UNKNOWN_12(2));
++
++	u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80;
++	bitsl(&ithc->regs->spi_config,
++		SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff),
++		SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize));
++
++	bitsl_set(&ithc->regs->quickspi_config2,
++		QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17);
++	bitsl(&ithc->regs->quickspi_config2,
++		QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT |
++		QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT |
++		QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0);
++
++	return 0;
++}
++
++static int wait_for_report(struct ithc *ithc)
++{
++	CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status,
++		DMA_RX_STATUS_READY, DMA_RX_STATUS_READY);
++	writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status);
++
++	u32 h = readl(&ithc->regs->input_header);
++	ithc_log_regs(ithc);
++	if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE
++		|| INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) {
++		pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h);
++		return -ENODATA;
++	}
++	return INPUT_HEADER_REPORT_LENGTH(h) * 4;
++}
++
++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg)
++{
++	pci_dbg(ithc->pci, "initializing HIDSPI\n");
++
++	// HIDSPI initialization sequence:
++	// "1. The host shall invoke the ACPI reset method to clear the device state."
++	acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL);
++	if (ACPI_FAILURE(s)) {
++		pci_err(ithc->pci, "ACPI reset failed\n");
++		return -EIO;
++	}
++
++	bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
++
++	// "2. Within 1 second, the device shall signal an interrupt and make available to the host
++	// an input report containing a device reset response."
++	int size = wait_for_report(ithc);
++	if (size < 0)
++		return size;
++	if (size < sizeof(struct hidspi_header)) {
++		pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size);
++		return -EMSGSIZE;
++	}
++
++	// "3. The host shall read the reset response from the device at the Input Report addresses
++	// specified in ACPI."
++	u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000;
++	struct {
++		struct hidspi_header header;
++		union {
++			struct hidspi_device_descriptor device_desc;
++			u32 data[16];
++		};
++	} resp = { 0 };
++	if (size > sizeof(resp)) {
++		pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size);
++		return -EMSGSIZE;
++	}
++	CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp);
++	if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) {
++		pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type);
++		return -ENOMSG;
++	}
++
++	// "4. The host shall then write an Output Report to the device at the Output Report Address
++	// specified in ACPI, requesting the Device Descriptor from the device."
++	u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000;
++	struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST };
++	CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req);
++
++	// "5. Within 1 second, the device shall signal an interrupt and make available to the host
++	// an input report containing the Device Descriptor."
++	size = wait_for_report(ithc);
++	if (size < 0)
++		return size;
++	if (size < sizeof(resp.header) + sizeof(resp.device_desc)) {
++		pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size);
++		return -EMSGSIZE;
++	}
++
++	// "6. The host shall read the Device Descriptor from the Input Report addresses specified
++	// in ACPI."
++	if (size > sizeof(resp)) {
++		pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size);
++		return -EMSGSIZE;
++	}
++	memset(&resp, 0, sizeof(resp));
++	CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp);
++	if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) {
++		pci_err(ithc->pci, "received type %i instead of device descriptor\n",
++			resp.header.type);
++		return -ENOMSG;
++	}
++	struct hidspi_device_descriptor *d = &resp.device_desc;
++	if (resp.header.len < sizeof(*d)) {
++		pci_err(ithc->pci, "response too small for device descriptor (%u)\n",
++			resp.header.len);
++		return -EMSGSIZE;
++	}
++	if (d->wDeviceDescLength != sizeof(*d)) {
++		pci_err(ithc->pci, "invalid device descriptor length (%u)\n",
++			d->wDeviceDescLength);
++		return -EMSGSIZE;
++	}
++
++	pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n",
++		d->bcdVersion, d->wReportDescLength,
++		d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength,
++		d->wVendorID, d->wProductID, d->wVersionID,
++		d->wFlags, d->dwReserved);
++
++	ithc->vendor_id = d->wVendorID;
++	ithc->product_id = d->wProductID;
++	ithc->product_rev = d->wVersionID;
++	ithc->max_rx_size = max_t(u32, d->wMaxInputLength,
++		d->wReportDescLength + sizeof(struct hidspi_header));
++	ithc->max_tx_size = d->wMaxOutputLength;
++	ithc->have_config = true;
++
++	// "7. The device and host shall then enter their "Ready" states - where the device may
++	// begin sending Input Reports, and the device shall be prepared for Output Reports from
++	// the host."
++
++	return 0;
++}
++
++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg)
++{
++	bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE);
++	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED);
++
++	ithc_log_regs(ithc);
++	CHECK_RET(ithc_quickspi_init_regs, ithc, cfg);
++	ithc_log_regs(ithc);
++	CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg);
++	ithc_log_regs(ithc);
++
++	// This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here,
++	// otherwise DMA will not work. Maybe selects between DMA and PIO mode?
++	bitsl(&ithc->regs->quickspi_config1,
++		QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1));
++
++	// TODO Do we need to set any of the following bits here?
++	//bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4);
++	//bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5);
++	//bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5);
++	//bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3);
++	//bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31);
++
++	ithc_log_regs(ithc);
++
++	return 0;
++}
++
++void ithc_quickspi_exit(struct ithc *ithc)
++{
++	// TODO Should we send HIDSPI 'power off' command?
++	//struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, };
++	//struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) };
++	//CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command()
++}
++
++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest)
++{
++	const struct hidspi_header *hdr = src;
++
++	if (len < sizeof(*hdr))
++		return -ENODATA;
++	// TODO Do we need to handle HIDSPI packet fragmentation?
++	if (len < sizeof(*hdr) + hdr->len)
++		return -EMSGSIZE;
++	if (len > round_up(sizeof(*hdr) + hdr->len, 4))
++		return -EMSGSIZE;
++
++	switch (hdr->type) {
++	case HIDSPI_INPUT_TYPE_RESET_RESPONSE:
++		// TODO "When the device detects an error condition, it may interrupt and make
++		// available to the host an Input Report containing an unsolicited Reset Response.
++		// After receiving an unsolicited Reset Response, the host shall initiate the
++		// request procedure from step (4) in the [HIDSPI initialization] process."
++		dest->type = ITHC_DATA_ERROR;
++		return 0;
++	case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR:
++		dest->type = ITHC_DATA_REPORT_DESCRIPTOR;
++		dest->data = hdr + 1;
++		dest->size = hdr->len;
++		return 0;
++	case HIDSPI_INPUT_TYPE_DATA:
++	case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE:
++		dest->type = ITHC_DATA_INPUT_REPORT;
++		dest->data = &hdr->id;
++		dest->size = hdr->len + 1;
++		return 0;
++	case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE:
++		dest->type = ITHC_DATA_GET_FEATURE;
++		dest->data = &hdr->id;
++		dest->size = hdr->len + 1;
++		return 0;
++	case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE:
++	case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE:
++		dest->type = ITHC_DATA_IGNORE;
++		return 0;
++	default:
++		return -EINVAL;
++	}
++}
++
++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest,
++	size_t maxlen)
++{
++	struct hidspi_header *hdr = dest;
++
++	size_t src_size = src->size;
++	const u8 *src_data = src->data;
++	u8 type;
++
++	switch (src->type) {
++	case ITHC_DATA_SET_FEATURE:
++		type = HIDSPI_OUTPUT_TYPE_SET_FEATURE;
++		break;
++	case ITHC_DATA_GET_FEATURE:
++		type = HIDSPI_OUTPUT_TYPE_GET_FEATURE;
++		break;
++	case ITHC_DATA_OUTPUT_REPORT:
++		type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT;
++		break;
++	case ITHC_DATA_REPORT_DESCRIPTOR:
++		type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST;
++		src_size = 0;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	u8 id = 0;
++	if (src_size) {
++		id = *src_data++;
++		src_size--;
++	}
++
++	// Data must be padded to next 4-byte boundary.
++	size_t padded = round_up(src_size, 4);
++	if (sizeof(*hdr) + padded > maxlen)
++		return -EOVERFLOW;
++
++	// Fill the TX buffer with header and data.
++	hdr->type = type;
++	hdr->len = (u16)src_size;
++	hdr->id = id;
++	memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0);
++
++	return sizeof(*hdr) + padded;
++}
++
+diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h
+new file mode 100644
+index 000000000000..74d882f6b2f0
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-quickspi.h
+@@ -0,0 +1,39 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++struct ithc_acpi_config {
++	bool has_config: 1;
++	bool has_input_report_header_address: 1;
++	bool has_input_report_body_address: 1;
++	bool has_output_report_body_address: 1;
++	bool has_read_opcode: 1;
++	bool has_write_opcode: 1;
++	bool has_read_mode: 1;
++	bool has_write_mode: 1;
++	bool has_spi_frequency: 1;
++	bool has_limit_packet_size: 1;
++	bool has_tx_delay: 1;
++	bool has_active_ltr: 1;
++	bool has_idle_ltr: 1;
++	u32 input_report_header_address;
++	u32 input_report_body_address;
++	u32 output_report_body_address;
++	u8 read_opcode;
++	u8 write_opcode;
++	u8 read_mode;
++	u8 write_mode;
++	u32 spi_frequency;
++	u32 limit_packet_size;
++	u32 tx_delay; // us/10 // TODO use?
++	u32 active_ltr; // ns/1024
++	u32 idle_ltr; // ns/1024
++};
++
++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg);
++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg);
++
++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg);
++void ithc_quickspi_exit(struct ithc *ithc);
++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest);
++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest,
++	size_t maxlen);
++
+diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c
+index e058721886e3..c0f13506af20 100644
+--- a/drivers/hid/ithc/ithc-regs.c
++++ b/drivers/hid/ithc/ithc-regs.c
+@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val)
+ 
+ int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val)
+ {
++	ithc_log_regs(ithc);
+ 	pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n",
+ 		reg_num(reg), mask, val);
+ 	u32 x;
+ 	if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) {
++		ithc_log_regs(ithc);
+ 		pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n",
+ 			reg_num(reg), mask, val);
+ 		return -ETIMEDOUT;
+ 	}
++	ithc_log_regs(ithc);
+ 	pci_dbg(ithc->pci, "done waiting\n");
+ 	return 0;
+ }
+ 
+ int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val)
+ {
++	ithc_log_regs(ithc);
+ 	pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n",
+ 		reg_num(reg), mask, val);
+ 	u8 x;
+ 	if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) {
++		ithc_log_regs(ithc);
+ 		pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n",
+ 			reg_num(reg), mask, val);
+ 		return -ETIMEDOUT;
+ 	}
++	ithc_log_regs(ithc);
+ 	pci_dbg(ithc->pci, "done waiting\n");
+ 	return 0;
+ }
+ 
+-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode)
++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale)
+ {
+-	pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode);
+-	if (mode == 3)
+-		mode = 2;
++	unsigned int s = 0;
++	u64 v = *ns;
++	while (v > 0x3ff) {
++		s++;
++		v >>= 5;
++	}
++	if (s > 5) {
++		s = 5;
++		v = 0x3ff;
++	}
++	*val = v;
++	*scale = s;
++	*ns = v << (5 * s);
++}
++
++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns)
++{
++	unsigned int active_val, active_scale, idle_val, idle_scale;
++	calc_ltr(&active_ltr_ns, &active_val, &active_scale);
++	calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale);
++	pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n",
++		active_ltr_ns, idle_ltr_ns);
++	writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY |
++		LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) |
++		LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val),
++		&ithc->regs->ltr_config);
++}
++
++void ithc_set_ltr_idle(struct ithc *ithc)
++{
++	u32 ltr = readl(&ithc->regs->ltr_config);
++	switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) {
++	case LTR_CONFIG_STATUS_IDLE:
++		break;
++	case LTR_CONFIG_STATUS_ACTIVE:
++		writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config);
++		break;
++	default:
++		pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr);
++		break;
++	}
++}
++
++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode)
++{
++	if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD)
++		return -EINVAL;
++	static const char * const modes[] = { "single", "dual", "quad" };
++	pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n",
++		SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)),
++		modes[read_mode], modes[write_mode]);
+ 	bitsl(&ithc->regs->spi_config,
+-		SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff),
+-		SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed));
++		SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) |
++		SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) |
++		SPI_CONFIG_CLKDIV_8,
++		SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) |
++		SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) |
++		(clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0));
+ 	return 0;
+ }
+ 
+ int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data)
+ {
+-	pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset);
++	pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset);
+ 	if (size > sizeof(ithc->regs->spi_cmd.data))
+ 		return -EINVAL;
+ 
+diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h
+index d4007d9e2bac..a9d236454644 100644
+--- a/drivers/hid/ithc/ithc-regs.h
++++ b/drivers/hid/ithc/ithc-regs.h
+@@ -1,14 +1,34 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+ 
++#define LTR_CONFIG_ENABLE_ACTIVE            BIT(0)
++#define LTR_CONFIG_TOGGLE                   BIT(1)
++#define LTR_CONFIG_ENABLE_IDLE              BIT(2)
++#define LTR_CONFIG_APPLY                    BIT(3)
++#define LTR_CONFIG_IDLE_LTR_SCALE(x)        (((x) & 7) << 4)
++#define LTR_CONFIG_IDLE_LTR_VALUE(x)        (((x) & 0x3ff) << 7)
++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x)      (((x) & 7) << 17)
++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x)      (((x) & 0x3ff) << 20)
++#define LTR_CONFIG_STATUS_ACTIVE            BIT(30)
++#define LTR_CONFIG_STATUS_IDLE              BIT(31)
++
+ #define CONTROL_QUIESCE                     BIT(1)
+ #define CONTROL_IS_QUIESCED                 BIT(2)
+ #define CONTROL_NRESET                      BIT(3)
++#define CONTROL_UNKNOWN_24(x)               (((x) & 3) << 24)
+ #define CONTROL_READY                       BIT(29)
+ 
+-#define SPI_CONFIG_MODE(x)                  (((x) & 3) << 2)
+-#define SPI_CONFIG_SPEED(x)                 (((x) & 7) << 4)
+-#define SPI_CONFIG_UNKNOWN_18(x)            (((x) & 3) << 18)
+-#define SPI_CONFIG_SPEED2(x)                (((x) & 0xf) << 20) // high bit = high speed mode?
++#define SPI_CONFIG_READ_MODE(x)             (((x) & 3) << 2)
++#define SPI_CONFIG_READ_CLKDIV(x)           (((x) & 7) << 4)
++#define SPI_CONFIG_READ_PACKET_SIZE(x)      (((x) & 0x1ff) << 7)
++#define SPI_CONFIG_WRITE_MODE(x)            (((x) & 3) << 18)
++#define SPI_CONFIG_WRITE_CLKDIV(x)          (((x) & 7) << 20)
++#define SPI_CONFIG_CLKDIV_8                 BIT(23) // additionally divide clk by 8, for both read and write
++#define SPI_CONFIG_WRITE_PACKET_SIZE(x)     (((x) & 0xff) << 24)
++
++#define SPI_CLK_FREQ_BASE                   125000000
++#define SPI_MODE_SINGLE                     0
++#define SPI_MODE_DUAL                       1
++#define SPI_MODE_QUAD                       2
+ 
+ #define ERROR_CONTROL_UNKNOWN_0             BIT(0)
+ #define ERROR_CONTROL_DISABLE_DMA           BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs
+@@ -53,33 +73,71 @@
+ #define DMA_TX_STATUS_UNKNOWN_2             BIT(2)
+ #define DMA_TX_STATUS_UNKNOWN_3             BIT(3) // busy?
+ 
++#define INPUT_HEADER_VERSION(x)             ((x) & 0xf)
++#define INPUT_HEADER_REPORT_LENGTH(x)       (((x) >> 8) & 0x3fff)
++#define INPUT_HEADER_SYNC(x)                ((x) >> 24)
++#define INPUT_HEADER_VERSION_VALUE          3
++#define INPUT_HEADER_SYNC_VALUE             0x5a
++
++#define QUICKSPI_CONFIG1_UNKNOWN_0(x)       (((x) & 0x1f) << 0)
++#define QUICKSPI_CONFIG1_UNKNOWN_5(x)       (((x) & 0x1f) << 5)
++#define QUICKSPI_CONFIG1_UNKNOWN_10(x)      (((x) & 0x1f) << 10)
++#define QUICKSPI_CONFIG1_UNKNOWN_16(x)      (((x) & 0xffff) << 16)
++
++#define QUICKSPI_CONFIG2_UNKNOWN_0(x)       (((x) & 0x1f) << 0)
++#define QUICKSPI_CONFIG2_UNKNOWN_5(x)       (((x) & 0x1f) << 5)
++#define QUICKSPI_CONFIG2_UNKNOWN_12(x)      (((x) & 0xf) << 12)
++#define QUICKSPI_CONFIG2_UNKNOWN_16         BIT(16)
++#define QUICKSPI_CONFIG2_UNKNOWN_17         BIT(17)
++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT  BIT(24)
++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25)
++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE     BIT(27)
++#define QUICKSPI_CONFIG2_IRQ_POLARITY       BIT(28)
++
+ #define DMA_RX_CONTROL_ENABLE               BIT(0)
+ #define DMA_RX_CONTROL_IRQ_UNKNOWN_1        BIT(1) // rx1 only?
+ #define DMA_RX_CONTROL_IRQ_ERROR            BIT(3) // rx1 only?
+-#define DMA_RX_CONTROL_IRQ_UNKNOWN_4        BIT(4) // rx0 only?
++#define DMA_RX_CONTROL_IRQ_READY            BIT(4) // rx0 only
+ #define DMA_RX_CONTROL_IRQ_DATA             BIT(5)
+ 
++#define DMA_RX_CONTROL2_UNKNOWN_4           BIT(4) // rx1 only?
+ #define DMA_RX_CONTROL2_UNKNOWN_5           BIT(5) // rx0 only?
+ #define DMA_RX_CONTROL2_RESET               BIT(7) // resets ringbuffer indices
+ 
+ #define DMA_RX_WRAP_FLAG                    BIT(7)
+ 
+ #define DMA_RX_STATUS_ERROR                 BIT(3)
+-#define DMA_RX_STATUS_UNKNOWN_4             BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms)
++#define DMA_RX_STATUS_READY                 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms)
+ #define DMA_RX_STATUS_HAVE_DATA             BIT(5)
+ #define DMA_RX_STATUS_ENABLED               BIT(8)
+ 
++#define INIT_UNKNOWN_GUC_2                  BIT(2)
++#define INIT_UNKNOWN_3                      BIT(3)
++#define INIT_UNKNOWN_GUC_4                  BIT(4)
++#define INIT_UNKNOWN_5                      BIT(5)
++#define INIT_UNKNOWN_31                     BIT(31)
++
+ // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC.
+ #define COUNTER_RESET                       BIT(31)
+ 
+ struct ithc_registers {
+-	/* 0000 */ u32 _unknown_0000[1024];
++	/* 0000 */ u32 _unknown_0000[5];
++	/* 0014 */ u32 ltr_config;
++	/* 0018 */ u32 _unknown_0018[1018];
+ 	/* 1000 */ u32 _unknown_1000;
+ 	/* 1004 */ u32 _unknown_1004;
+ 	/* 1008 */ u32 control_bits;
+ 	/* 100c */ u32 _unknown_100c;
+ 	/* 1010 */ u32 spi_config;
+-	/* 1014 */ u32 _unknown_1014[3];
++	/* 1014 */ u8 read_opcode; // maybe for header?
++	/* 1015 */ u8 read_opcode_quad;
++	/* 1016 */ u8 read_opcode_dual;
++	/* 1017 */ u8 read_opcode_single;
++	/* 1018 */ u8 write_opcode; // not used?
++	/* 1019 */ u8 write_opcode_quad;
++	/* 101a */ u8 write_opcode_dual;
++	/* 101b */ u8 write_opcode_single;
++	/* 101c */ u32 _unknown_101c;
+ 	/* 1020 */ u32 error_control;
+ 	/* 1024 */ u32 error_status; // write to clear
+ 	/* 1028 */ u32 error_flags; // write to clear
+@@ -100,12 +158,19 @@ struct ithc_registers {
+ 		/* 109a */ u8 _unknown_109a;
+ 		/* 109b */ u8 num_prds;
+ 		/* 109c */ u32 status; // write to clear
++		/* 10a0 */ u32 _unknown_10a0[5];
++		/* 10b4 */ u32 spi_addr;
+ 	} dma_tx;
+-	/* 10a0 */ u32 _unknown_10a0[7];
+-	/* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET
++	/* 10b8 */ u32 spi_header_addr;
++	union {
++		/* 10bc */ u32 irq_cause; // in legacy THC mode
++		/* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec)
++	};
+ 	/* 10c0 */ u32 _unknown_10c0[8];
+ 	/* 10e0 */ u32 _unknown_10e0_counters[3];
+-	/* 10ec */ u32 _unknown_10ec[5];
++	/* 10ec */ u32 quickspi_config1;
++	/* 10f0 */ u32 quickspi_config2;
++	/* 10f4 */ u32 _unknown_10f4[3];
+ 	struct {
+ 		/* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq()
+ 		/* 1108/1208 */ u8 num_bufs;
+@@ -120,70 +185,30 @@ struct ithc_registers {
+ 		/* 1118/1218 */ u64 _unknown_1118_guc_addr;
+ 		/* 1120/1220 */ u32 _unknown_1120_guc;
+ 		/* 1124/1224 */ u32 _unknown_1124_guc;
+-		/* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related
++		/* 1128/1228 */ u32 init_unknown;
+ 		/* 112c/122c */ u32 _unknown_112c;
+ 		/* 1130/1230 */ u64 _unknown_1130_guc_addr;
+ 		/* 1138/1238 */ u32 _unknown_1138_guc;
+ 		/* 113c/123c */ u32 _unknown_113c;
+ 		/* 1140/1240 */ u32 _unknown_1140_guc;
+-		/* 1144/1244 */ u32 _unknown_1144[23];
++		/* 1144/1244 */ u32 _unknown_1144[11];
++		/* 1170/1270 */ u32 spi_addr;
++		/* 1174/1274 */ u32 _unknown_1174[11];
+ 		/* 11a0/12a0 */ u32 _unknown_11a0_counters[6];
+ 		/* 11b8/12b8 */ u32 _unknown_11b8[18];
+ 	} dma_rx[2];
+ };
+ static_assert(sizeof(struct ithc_registers) == 0x1300);
+ 
+-#define DEVCFG_DMA_RX_SIZE(x)          ((((x) & 0x3fff) + 1) << 6)
+-#define DEVCFG_DMA_TX_SIZE(x)          (((((x) >> 14) & 0x3ff) + 1) << 6)
+-
+-#define DEVCFG_TOUCH_MASK              0x3f
+-#define DEVCFG_TOUCH_ENABLE            BIT(0)
+-#define DEVCFG_TOUCH_UNKNOWN_1         BIT(1)
+-#define DEVCFG_TOUCH_UNKNOWN_2         BIT(2)
+-#define DEVCFG_TOUCH_UNKNOWN_3         BIT(3)
+-#define DEVCFG_TOUCH_UNKNOWN_4         BIT(4)
+-#define DEVCFG_TOUCH_UNKNOWN_5         BIT(5)
+-#define DEVCFG_TOUCH_UNKNOWN_6         BIT(6)
+-
+-#define DEVCFG_DEVICE_ID_TIC           0x43495424 // "$TIC"
+-
+-#define DEVCFG_SPI_MAX_FREQ(x)         (((x) >> 1) & 0xf) // high bit = use high speed mode?
+-#define DEVCFG_SPI_MODE(x)             (((x) >> 6) & 3)
+-#define DEVCFG_SPI_UNKNOWN_8(x)        (((x) >> 8) & 0x3f)
+-#define DEVCFG_SPI_NEEDS_HEARTBEAT     BIT(20) // TODO implement heartbeat
+-#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7)
+-#define DEVCFG_SPI_UNKNOWN_25          BIT(25)
+-#define DEVCFG_SPI_UNKNOWN_26          BIT(26)
+-#define DEVCFG_SPI_UNKNOWN_27          BIT(27)
+-#define DEVCFG_SPI_DELAY(x)            (((x) >> 28) & 7) // TODO use this
+-#define DEVCFG_SPI_USE_EXT_READ_CFG    BIT(31) // TODO use this?
+-
+-struct ithc_device_config { // (Example values are from an SP7+.)
+-	u32 _unknown_00;      // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET)
+-	u32 _unknown_04;      // 04 = 0x00000000
+-	u32 dma_buf_sizes;    // 08 = 0x000a00ff
+-	u32 touch_cfg;        // 0c = 0x0000001c
+-	u32 _unknown_10;      // 10 = 0x0000001c
+-	u32 device_id;        // 14 = 0x43495424 = "$TIC"
+-	u32 spi_config;       // 18 = 0xfda00a2e
+-	u16 vendor_id;        // 1c = 0x045e = Microsoft Corp.
+-	u16 product_id;       // 1e = 0x0c1a
+-	u32 revision;         // 20 = 0x00000001
+-	u32 fw_version;       // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices)
+-	u32 _unknown_28;      // 28 = 0x00000000
+-	u32 fw_mode;          // 2c = 0x00000000 (for fw update?)
+-	u32 _unknown_30;      // 30 = 0x00000000
+-	u32 _unknown_34;      // 34 = 0x0404035e (u8,u8,u8,u8 = version?)
+-	u32 _unknown_38;      // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET)
+-	u32 _unknown_3c;      // 3c = 0x00000002
+-};
+-
+ void bitsl(__iomem u32 *reg, u32 mask, u32 val);
+ void bitsb(__iomem u8 *reg, u8 mask, u8 val);
+ #define bitsl_set(reg, x) bitsl(reg, x, x)
+ #define bitsb_set(reg, x) bitsb(reg, x, x)
+ int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val);
+ int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val);
+-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode);
++
++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns);
++void ithc_set_ltr_idle(struct ithc *ithc);
++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode);
+ int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data);
+ 
+diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h
+index 028e55a4ec53..e90c38044432 100644
+--- a/drivers/hid/ithc/ithc.h
++++ b/drivers/hid/ithc/ithc.h
+@@ -1,20 +1,19 @@
+ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+ 
+-#include <linux/module.h>
+-#include <linux/input.h>
+-#include <linux/hid.h>
++#include <linux/acpi.h>
++#include <linux/debugfs.h>
++#include <linux/delay.h>
+ #include <linux/dma-mapping.h>
++#include <linux/hid.h>
+ #include <linux/highmem.h>
+-#include <linux/pci.h>
++#include <linux/input.h>
+ #include <linux/io-64-nonatomic-lo-hi.h>
+ #include <linux/iopoll.h>
+-#include <linux/delay.h>
+ #include <linux/kthread.h>
+ #include <linux/miscdevice.h>
+-#include <linux/debugfs.h>
++#include <linux/module.h>
++#include <linux/pci.h>
+ #include <linux/poll.h>
+-#include <linux/timer.h>
+-#include <linux/pm_qos.h>
+ 
+ #define DEVNAME "ithc"
+ #define DEVFULLNAME "Intel Touch Host Controller"
+@@ -27,10 +26,37 @@
+ 
+ #define NUM_RX_BUF 16
+ 
++// PCI device IDs:
++// Lakefield
++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1    0x98d0
++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2    0x98d1
++// Tiger Lake
++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0
++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1
++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1  0x43d0
++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2  0x43d1
++// Alder Lake
++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1  0x7ad8
++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2  0x7ad9
++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1  0x51d0
++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2  0x51d1
++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1  0x54d0
++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2  0x54d1
++// Raptor Lake
++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1  0x7a58
++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2  0x7a59
++// Meteor Lake
++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1    0x7e48
++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2    0x7e4a
++
+ struct ithc;
+ 
+ #include "ithc-regs.h"
++#include "ithc-hid.h"
+ #include "ithc-dma.h"
++#include "ithc-legacy.h"
++#include "ithc-quickspi.h"
++#include "ithc-debug.h"
+ 
+ struct ithc {
+ 	char phys[32];
+@@ -38,30 +64,21 @@ struct ithc {
+ 	int irq;
+ 	struct task_struct *poll_thread;
+ 
+-	struct pm_qos_request activity_qos;
+-	struct hrtimer activity_start_timer;
+-	struct hrtimer activity_end_timer;
+-	ktime_t last_rx_time;
+-	unsigned int cur_rx_seq_count;
+-	unsigned int cur_rx_seq_errors;
+-
+-	struct hid_device *hid;
+-	bool hid_parse_done;
+-	wait_queue_head_t wait_hid_parse;
+-	wait_queue_head_t wait_hid_get_feature;
+-	struct mutex hid_get_feature_mutex;
+-	void *hid_get_feature_buf;
+-	size_t hid_get_feature_size;
+-
+ 	struct ithc_registers __iomem *regs;
+ 	struct ithc_registers *prev_regs; // for debugging
+-	struct ithc_device_config config;
+ 	struct ithc_dma_rx dma_rx[2];
+ 	struct ithc_dma_tx dma_tx;
++	struct ithc_hid hid;
++
++	bool use_quickspi;
++	bool have_config;
++	u16 vendor_id;
++	u16 product_id;
++	u32 product_rev;
++	u32 max_rx_size;
++	u32 max_tx_size;
++	u32 legacy_touch_cfg;
+ };
+ 
+ int ithc_reset(struct ithc *ithc);
+-void ithc_set_active(struct ithc *ithc, unsigned int duration_us);
+-int ithc_debug_init(struct ithc *ithc);
+-void ithc_log_regs(struct ithc *ithc);
+ 
+-- 
+2.44.0
+

+ 54 - 0
patches/6.8/0006-surface-sam.patch

@@ -1162,3 +1162,57 @@ index a5a3941b3f43..e54d0a8f7daa 100644
 -- 
 2.44.0
 
+From 63781a056a0f06d5cc38d7755e0753c7ec08c51c Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Fri, 19 Apr 2024 20:41:47 +0200
+Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is
+ destroyed in probe
+
+There is a small window in ssam_serial_hub_probe() where the controller
+is initialized but has not been started yet. Specifically, between
+ssam_controller_init() and ssam_controller_start(). Any failure in this
+window, for example caused by a failure of serdev_device_open(),
+currently results in an incorrect warning being emitted.
+
+In particular, any failure in this window results in the controller
+being destroyed via ssam_controller_destroy(). This function checks the
+state of the controller and, in an attempt to validate that the
+controller has been cleanly shut down before we try and deallocate any
+resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED.
+
+However, since we have only just initialized the controller and have not
+yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this
+is the only point at which the controller has this state, as it will
+change after we start the controller with ssam_controller_start() and
+never revert back. Further, at this point no communication has taken
+place and the sender and receiver threads have not been started yet (and
+we may not even have an open serdev device either).
+
+Therefore, it is perfectly safe to call ssam_controller_destroy() with a
+state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the
+warning currently being emitted is incorrect. Fix it by extending the
+check.
+
+Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem")
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
+---
+ drivers/platform/surface/aggregator/controller.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
+index 7fc602e01487..7e89f547999b 100644
+--- a/drivers/platform/surface/aggregator/controller.c
++++ b/drivers/platform/surface/aggregator/controller.c
+@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl)
+ 	if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED)
+ 		return;
+ 
+-	WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED);
++	WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED &&
++		ctrl->state != SSAM_CONTROLLER_INITIALIZED);
+ 
+ 	/*
+ 	 * Note: New events could still have been received after the previous
+-- 
+2.44.0
+