فهرست منبع

fixup! Add patches for 6.13

Maximilian Luz 4 ماه پیش
والد
کامیت
e6b1951c2a

+ 2730 - 0
patches/6.13/0006-ithc.patch

@@ -39,3 +39,2733 @@ index 466c1412dd45..565686813588 100644
 -- 
 2.48.1
 
+From 4a1179f85e091a21417cc81b5e3813dbcc996107 Mon Sep 17 00:00:00 2001
+From: quo <tuple@list.ru>
+Date: Sun, 11 Dec 2022 12:10:54 +0100
+Subject: [PATCH] hid: Add support for Intel Touch Host Controller
+
+Based on quo/ithc-linux@34539af4726d.
+
+Signed-off-by: Maximilian Stoll <luzmaximilian@gmail.com>
+Patchset: ithc
+---
+ drivers/hid/Kconfig              |   2 +
+ drivers/hid/Makefile             |   1 +
+ drivers/hid/ithc/Kbuild          |   6 +
+ drivers/hid/ithc/Kconfig         |  12 +
+ drivers/hid/ithc/ithc-debug.c    | 149 ++++++++
+ drivers/hid/ithc/ithc-debug.h    |   7 +
+ drivers/hid/ithc/ithc-dma.c      | 312 ++++++++++++++++
+ drivers/hid/ithc/ithc-dma.h      |  47 +++
+ drivers/hid/ithc/ithc-hid.c      | 207 +++++++++++
+ drivers/hid/ithc/ithc-hid.h      |  32 ++
+ drivers/hid/ithc/ithc-legacy.c   | 254 +++++++++++++
+ drivers/hid/ithc/ithc-legacy.h   |   8 +
+ drivers/hid/ithc/ithc-main.c     | 431 ++++++++++++++++++++++
+ drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++
+ drivers/hid/ithc/ithc-quickspi.h |  39 ++
+ drivers/hid/ithc/ithc-regs.c     | 154 ++++++++
+ drivers/hid/ithc/ithc-regs.h     | 211 +++++++++++
+ drivers/hid/ithc/ithc.h          |  89 +++++
+ 18 files changed, 2568 insertions(+)
+ create mode 100644 drivers/hid/ithc/Kbuild
+ create mode 100644 drivers/hid/ithc/Kconfig
+ create mode 100644 drivers/hid/ithc/ithc-debug.c
+ create mode 100644 drivers/hid/ithc/ithc-debug.h
+ create mode 100644 drivers/hid/ithc/ithc-dma.c
+ create mode 100644 drivers/hid/ithc/ithc-dma.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-main.c
+ create mode 100644 drivers/hid/ithc/ithc-quickspi.c
+ create mode 100644 drivers/hid/ithc/ithc-quickspi.h
+ create mode 100644 drivers/hid/ithc/ithc-regs.c
+ create mode 100644 drivers/hid/ithc/ithc-regs.h
+ create mode 100644 drivers/hid/ithc/ithc.h
+
+diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
+index ce8e61de72c7..db6665977a32 100644
+--- a/drivers/hid/Kconfig
++++ b/drivers/hid/Kconfig
+@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig"
+ 
+ source "drivers/hid/ipts/Kconfig"
+ 
++source "drivers/hid/ithc/Kconfig"
++
+ endif # HID_SUPPORT
+diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
+index c33ea76797a7..6a89c1eb1b19 100644
+--- a/drivers/hid/Makefile
++++ b/drivers/hid/Makefile
+@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID)       += amd-sfh-hid/
+ obj-$(CONFIG_SURFACE_HID_CORE)  += surface-hid/
+ 
+ obj-$(CONFIG_HID_IPTS)          += ipts/
++obj-$(CONFIG_HID_ITHC)          += ithc/
+diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild
+new file mode 100644
+index 000000000000..4937ba131297
+--- /dev/null
++++ b/drivers/hid/ithc/Kbuild
+@@ -0,0 +1,6 @@
++obj-$(CONFIG_HID_ITHC) := ithc.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/Kconfig b/drivers/hid/ithc/Kconfig
+new file mode 100644
+index 000000000000..ede713023609
+--- /dev/null
++++ b/drivers/hid/ithc/Kconfig
+@@ -0,0 +1,12 @@
++config HID_ITHC
++	tristate "Intel Touch Host Controller"
++	depends on PCI
++	depends on HID
++	help
++	  Say Y here if your system has a touchscreen using Intels
++	  Touch Host Controller (ITHC / IPTS) technology.
++
++	  If unsure say N.
++
++	  To compile this driver as a module, choose M here: the
++	  module will be called ithc.
+diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c
+new file mode 100644
+index 000000000000..2d8c6afe9966
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-debug.c
+@@ -0,0 +1,149 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++void ithc_log_regs(struct ithc *ithc)
++{
++	if (!ithc->prev_regs)
++		return;
++	u32 __iomem *cur = (__iomem void *)ithc->regs;
++	u32 *prev = (void *)ithc->prev_regs;
++	for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) {
++		u32 x = readl(cur + i);
++		if (x != prev[i]) {
++			pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x);
++			prev[i] = x;
++		}
++	}
++}
++
++static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len,
++	loff_t *offset)
++{
++	// Debug commands consist of a single letter followed by a list of numbers (decimal or
++	// hexadecimal, space-separated).
++	struct ithc *ithc = file_inode(f)->i_private;
++	char cmd[256];
++	if (!ithc || !ithc->pci)
++		return -ENODEV;
++	if (!len)
++		return -EINVAL;
++	if (len >= sizeof(cmd))
++		return -EINVAL;
++	if (copy_from_user(cmd, buf, len))
++		return -EFAULT;
++	cmd[len] = 0;
++	if (cmd[len-1] == '\n')
++		cmd[len-1] = 0;
++	pci_info(ithc->pci, "debug command: %s\n", cmd);
++
++	// Parse the list of arguments into a u32 array.
++	u32 n = 0;
++	const char *s = cmd + 1;
++	u32 a[32];
++	while (*s && *s != '\n') {
++		if (n >= ARRAY_SIZE(a))
++			return -EINVAL;
++		if (*s++ != ' ')
++			return -EINVAL;
++		char *e;
++		a[n++] = simple_strtoul(s, &e, 0);
++		if (e == s)
++			return -EINVAL;
++		s = e;
++	}
++	ithc_log_regs(ithc);
++
++	// Execute the command.
++	switch (cmd[0]) {
++	case 'x': // reset
++		ithc_reset(ithc);
++		break;
++	case 'w': // write register: offset mask value
++		if (n != 3 || (a[0] & 3))
++			return -EINVAL;
++		pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n",
++			a[0], a[2], a[1]);
++		bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]);
++		break;
++	case 'r': // read register: offset
++		if (n != 1 || (a[0] & 3))
++			return -EINVAL;
++		pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0],
++			readl(((__iomem u32 *)ithc->regs) + a[0] / 4));
++		break;
++	case 's': // spi command: cmd offset len data...
++		// read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
++		// set touch cfg: s 6 12 4 XX
++		if (n < 3 || a[2] > (n - 3) * 4)
++			return -EINVAL;
++		pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]);
++		if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3))
++			for (u32 i = 0; i < (a[2] + 3) / 4; i++)
++				pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]);
++		break;
++	case 'd': // dma command: cmd len data...
++		// get report descriptor: d 7 8 0 0
++		// enable multitouch: d 3 2 0x0105
++		if (n < 1)
++			return -EINVAL;
++		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:
++		return -EINVAL;
++	}
++	ithc_log_regs(ithc);
++	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,
++};
++
++static void ithc_debugfs_devres_release(struct device *dev, void *res)
++{
++	struct dentry **dbgm = res;
++	debugfs_remove_recursive(*dbgm);
++}
++
++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(pci_name(ithc->pci), dbg_dir);
++	if (IS_ERR(dbg))
++		return PTR_ERR(dbg);
++	*dbgm = dbg;
++
++	struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd);
++	if (IS_ERR(cmd))
++		return PTR_ERR(cmd);
++
++	return 0;
++}
++
+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
+new file mode 100644
+index 000000000000..bf4eab33062b
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-dma.c
+@@ -0,0 +1,312 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers.
++// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags.
++// This allows each data buffer to consist of multiple non-contiguous blocks of memory.
++
++static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p,
++	unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir)
++{
++	p->num_pages = num_pages;
++	p->dir = dir;
++	// We allocate enough space to have one PRD per data buffer page, however if the data
++	// buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so
++	// some will remain unused (which is fine).
++	p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE);
++	p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL);
++	if (!p->addr)
++		return -ENOMEM;
++	if (p->dma_addr & (PAGE_SIZE - 1))
++		return -EFAULT;
++	return 0;
++}
++
++// Devres managed sg_table wrapper.
++struct ithc_sg_table {
++	void *addr;
++	struct sg_table sgt;
++	enum dma_data_direction dir;
++};
++static void ithc_dma_sgtable_free(struct sg_table *sgt)
++{
++	struct scatterlist *sg;
++	int i;
++	for_each_sgtable_sg(sgt, sg, i) {
++		struct page *p = sg_page(sg);
++		if (p)
++			__free_page(p);
++	}
++	sg_free_table(sgt);
++}
++static void ithc_dma_data_devres_release(struct device *dev, void *res)
++{
++	struct ithc_sg_table *sgt = res;
++	if (sgt->addr)
++		vunmap(sgt->addr);
++	dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0);
++	ithc_dma_sgtable_free(&sgt->sgt);
++}
++
++static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
++	struct ithc_dma_data_buffer *b)
++{
++	// We don't use dma_alloc_coherent() for data buffers, because they don't have to be
++	// coherent (they are unidirectional) or contiguous (we can use one PRD per page).
++	// We could use dma_alloc_noncontiguous(), however this still always allocates a single
++	// DMA mapped segment, which is more restrictive than what we need.
++	// Instead we use an sg_table of individually allocated pages.
++	struct page *pages[16];
++	if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages))
++		return -EINVAL;
++	b->active_idx = -1;
++	struct ithc_sg_table *sgt = devres_alloc(
++		ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL);
++	if (!sgt)
++		return -ENOMEM;
++	sgt->dir = prds->dir;
++
++	if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) {
++		struct scatterlist *sg;
++		int i;
++		bool ok = true;
++		for_each_sgtable_sg(&sgt->sgt, sg, i) {
++			// NOTE: don't need __GFP_DMA for PCI DMA
++			struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
++			if (!p) {
++				ok = false;
++				break;
++			}
++			sg_set_page(sg, p, PAGE_SIZE, 0);
++		}
++		if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) {
++			devres_add(&ithc->pci->dev, sgt);
++			b->sgt = &sgt->sgt;
++			b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL);
++			if (!b->addr)
++				return -ENOMEM;
++			return 0;
++		}
++		ithc_dma_sgtable_free(&sgt->sgt);
++	}
++	devres_free(sgt);
++	return -ENOMEM;
++}
++
++static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
++	struct ithc_dma_data_buffer *b, unsigned int idx)
++{
++	// Give a buffer to the THC.
++	struct ithc_phys_region_desc *prd = prds->addr;
++	prd += idx * prds->num_pages;
++	if (b->active_idx >= 0) {
++		pci_err(ithc->pci, "buffer already active\n");
++		return -EINVAL;
++	}
++	b->active_idx = idx;
++	if (prds->dir == DMA_TO_DEVICE) {
++		// TX buffer: Caller should have already filled the data buffer, so just fill
++		// the PRD and flush.
++		// (TODO: Support multi-page TX buffers. So far no device seems to use or need
++		// these though.)
++		if (b->data_size > PAGE_SIZE)
++			return -EINVAL;
++		prd->addr = sg_dma_address(b->sgt->sgl) >> 10;
++		prd->size = b->data_size | PRD_FLAG_END;
++		flush_kernel_vmap_range(b->addr, b->data_size);
++	} else if (prds->dir == DMA_FROM_DEVICE) {
++		// RX buffer: Reset PRDs.
++		struct scatterlist *sg;
++		int i;
++		for_each_sgtable_dma_sg(b->sgt, sg, i) {
++			prd->addr = sg_dma_address(sg) >> 10;
++			prd->size = sg_dma_len(sg);
++			prd++;
++		}
++		prd[-1].size |= PRD_FLAG_END;
++	}
++	dma_wmb(); // for the prds
++	dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir);
++	return 0;
++}
++
++static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
++	struct ithc_dma_data_buffer *b, unsigned int idx)
++{
++	// Take a buffer from the THC.
++	struct ithc_phys_region_desc *prd = prds->addr;
++	prd += idx * prds->num_pages;
++	// This is purely a sanity check. We don't strictly need the idx parameter for this
++	// function, because it should always be the same as active_idx, unless we have a bug.
++	if (b->active_idx != idx) {
++		pci_err(ithc->pci, "wrong buffer index\n");
++		return -EINVAL;
++	}
++	b->active_idx = -1;
++	if (prds->dir == DMA_FROM_DEVICE) {
++		// RX buffer: Calculate actual received data size from PRDs.
++		dma_rmb(); // for the prds
++		b->data_size = 0;
++		struct scatterlist *sg;
++		int i;
++		for_each_sgtable_dma_sg(b->sgt, sg, i) {
++			unsigned int size = prd->size;
++			b->data_size += size & PRD_SIZE_MASK;
++			if (size & PRD_FLAG_END)
++				break;
++			if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) {
++				pci_err(ithc->pci, "truncated prd\n");
++				break;
++			}
++			prd++;
++		}
++		invalidate_kernel_vmap_range(b->addr, b->data_size);
++	}
++	dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir);
++	return 0;
++}
++
++int ithc_dma_rx_init(struct ithc *ithc, u8 channel)
++{
++	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
++	mutex_init(&rx->mutex);
++
++	// Allocate buffers.
++	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, 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]);
++
++	// Init registers.
++	writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2);
++	lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr);
++	writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs);
++	writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds);
++	u8 head = readb(&ithc->regs->dma_rx[channel].head);
++	if (head) {
++		pci_err(ithc->pci, "head is nonzero (%u)\n", head);
++		return -EIO;
++	}
++
++	// Init buffers.
++	for (unsigned int i = 0; i < NUM_RX_BUF; i++)
++		CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i);
++
++	writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail);
++	return 0;
++}
++
++void ithc_dma_rx_enable(struct ithc *ithc, u8 channel)
++{
++	bitsb_set(&ithc->regs->dma_rx[channel].control,
++		DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA);
++	CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status,
++		DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED);
++}
++
++int ithc_dma_tx_init(struct ithc *ithc)
++{
++	struct ithc_dma_tx *tx = &ithc->dma_tx;
++	mutex_init(&tx->mutex);
++
++	// Allocate buffers.
++	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",
++		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);
++
++	// Init registers.
++	lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr);
++	writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds);
++
++	// Init buffers.
++	CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
++	return 0;
++}
++
++static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
++{
++	// Process all filled RX buffers from the ringbuffer.
++	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
++	unsigned int n = rx->num_received;
++	u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head);
++	while (1) {
++		u8 tail = n % NUM_RX_BUF;
++		u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG);
++		writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail);
++		// ringbuffer is full if tail_wrap == head_wrap
++		// ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG
++		if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG))
++			return 0;
++
++		// take the buffer that the device just filled
++		struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF];
++		CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail);
++		rx->num_received = ++n;
++
++		// process data
++		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);
++	}
++}
++int ithc_dma_rx(struct ithc *ithc, u8 channel)
++{
++	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
++	mutex_lock(&rx->mutex);
++	int ret = ithc_dma_rx_unlocked(ithc, channel);
++	mutex_unlock(&rx->mutex);
++	return ret;
++}
++
++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data)
++{
++	// Send a single TX buffer to the THC.
++	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.
++	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);
++	CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0);
++	writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status);
++	return 0;
++}
++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, 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
+new file mode 100644
+index 000000000000..1749a5819b3e
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-dma.h
+@@ -0,0 +1,47 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++#define PRD_SIZE_MASK            0xffffff
++#define PRD_FLAG_END             0x1000000
++#define PRD_FLAG_SUCCESS         0x2000000
++#define PRD_FLAG_ERROR           0x4000000
++
++struct ithc_phys_region_desc {
++	u64 addr; // physical addr/1024
++	u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds
++	u32 unused;
++};
++
++struct ithc_dma_prd_buffer {
++	void *addr;
++	dma_addr_t dma_addr;
++	u32 size;
++	u32 num_pages; // per data buffer
++	enum dma_data_direction dir;
++};
++
++struct ithc_dma_data_buffer {
++	void *addr;
++	struct sg_table *sgt;
++	int active_idx;
++	u32 data_size;
++};
++
++struct ithc_dma_tx {
++	struct mutex mutex;
++	struct ithc_dma_prd_buffer prds;
++	struct ithc_dma_data_buffer buf;
++};
++
++struct ithc_dma_rx {
++	struct mutex mutex;
++	u32 num_received;
++	struct ithc_dma_prd_buffer prds;
++	struct ithc_dma_data_buffer bufs[NUM_RX_BUF];
++};
++
++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, 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..8883987fb352
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-legacy.c
+@@ -0,0 +1,254 @@
++// 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 ADL devices.
++	switch (ithc->pci->device) {
++	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1:
++	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2:
++	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
+new file mode 100644
+index 000000000000..ac56c253674b
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-main.c
+@@ -0,0 +1,431 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++MODULE_DESCRIPTION("Intel Touch Host Controller driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++static const struct pci_device_id ithc_pci_tbl[] = {
++	{
++		.vendor = PCI_VENDOR_ID_INTEL,
++		.device = PCI_ANY_ID,
++		.subvendor = PCI_ANY_ID,
++		.subdevice = PCI_ANY_ID,
++		.class = PCI_CLASS_INPUT_PEN << 8,
++		.class_mask = ~0,
++	},
++	{}
++};
++MODULE_DEVICE_TABLE(pci, ithc_pci_tbl);
++
++// Module parameters
++
++static bool ithc_use_polling = false;
++module_param_named(poll, ithc_use_polling, bool, 0);
++MODULE_PARM_DESC(poll, "Use polling instead of interrupts");
++
++// Since all known devices seem to use only channel 1, by default we disable channel 0.
++static bool ithc_use_rx0 = false;
++module_param_named(rx0, ithc_use_rx0, bool, 0);
++MODULE_PARM_DESC(rx0, "Use DMA RX channel 0");
++
++static bool ithc_use_rx1 = true;
++module_param_named(rx1, ithc_use_rx1, bool, 0);
++MODULE_PARM_DESC(rx1, "Use DMA RX channel 1");
++
++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)");
++
++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 unsigned int ithc_idle_delay_ms = 1000;
++module_param_named(idledelay, ithc_idle_delay_ms, uint, 0);
++MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)");
++
++static bool ithc_log_regs_enabled = false;
++module_param_named(logregs, ithc_log_regs_enabled, bool, 0);
++MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)");
++
++// Interrupts/polling
++
++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_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_READY | DMA_RX_STATUS_HAVE_DATA,
++		&ithc->regs->dma_rx[channel].status);
++}
++
++static void ithc_clear_interrupts(struct ithc *ithc)
++{
++	writel(0xffffffff, &ithc->regs->error_flags);
++	writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status);
++	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
++	ithc_clear_dma_rx_interrupts(ithc, 0);
++	ithc_clear_dma_rx_interrupts(ithc, 1);
++	writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2,
++		&ithc->regs->dma_tx.status);
++}
++
++static void ithc_idle_timer_callback(struct timer_list *t)
++{
++	struct ithc *ithc = container_of(t, struct ithc, idle_timer);
++	ithc_set_ltr_idle(ithc);
++}
++
++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 after a delay.
++	mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms));
++
++	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;
++
++	// 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)
++			pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n");
++	}
++
++	// Process DMA rx
++	if (ithc_use_rx0) {
++		ithc_clear_dma_rx_interrupts(ithc, 0);
++		if (rx0)
++			ithc_dma_rx(ithc, 0);
++	}
++	if (ithc_use_rx1) {
++		ithc_clear_dma_rx_interrupts(ithc, 1);
++		if (rx1)
++			ithc_dma_rx(ithc, 1);
++	}
++
++	ithc_log_regs(ithc);
++}
++
++static irqreturn_t ithc_interrupt_thread(int irq, void *arg)
++{
++	struct ithc *ithc = arg;
++	pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n",
++		readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags),
++		readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status),
++		readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status),
++		readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status),
++		readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status));
++	ithc_process(ithc);
++	return IRQ_HANDLED;
++}
++
++static int ithc_poll_thread(void *arg)
++{
++	struct ithc *ithc = arg;
++	unsigned int sleep = 100;
++	while (!kthread_should_stop()) {
++		u32 n = ithc->dma_rx[1].num_received;
++		ithc_process(ithc);
++		// Decrease polling interval to 20ms if we received data, otherwise slowly
++		// increase it up to 200ms.
++		sleep = n != ithc->dma_rx[1].num_received ? 20
++			: min(200u, sleep + (sleep >> 4) + 1);
++		msleep_interruptible(sleep);
++	}
++	return 0;
++}
++
++// Device initialization and shutdown
++
++static void ithc_disable(struct ithc *ithc)
++{
++	bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE);
++	CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED);
++	bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
++	bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0);
++	bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0);
++	bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0);
++	bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0);
++	ithc_disable_interrupts(ithc);
++	ithc_clear_interrupts(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);
++	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;
++
++	// 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 50us, 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
++		: 50 * 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);
++
++	return 0;
++}
++
++int ithc_reset(struct ithc *ithc)
++{
++	// FIXME This should probably do devres_release_group()+ithc_start().
++	// But because this is called during DMA processing, that would have to be done
++	// asynchronously (schedule_work()?). And with extra locking?
++	pci_err(ithc->pci, "reset\n");
++	CHECK(ithc_init_device, ithc);
++	if (ithc_use_rx0)
++		ithc_dma_rx_enable(ithc, 0);
++	if (ithc_use_rx1)
++		ithc_dma_rx_enable(ithc, 1);
++	ithc_log_regs(ithc);
++	pci_dbg(ithc->pci, "reset completed\n");
++	return 0;
++}
++
++static void ithc_stop(void *res)
++{
++	struct ithc *ithc = res;
++	pci_dbg(ithc->pci, "stopping\n");
++	ithc_log_regs(ithc);
++
++	if (ithc->poll_thread)
++		CHECK(kthread_stop, ithc->poll_thread);
++	if (ithc->irq >= 0)
++		disable_irq(ithc->irq);
++	if (ithc->use_quickspi)
++		ithc_quickspi_exit(ithc);
++	else
++		ithc_legacy_exit(ithc);
++	ithc_disable(ithc);
++	del_timer_sync(&ithc->idle_timer);
++
++	// Clear DMA config.
++	for (unsigned int i = 0; i < 2; i++) {
++		CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0);
++		lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr);
++		writeb(0, &ithc->regs->dma_rx[i].num_bufs);
++		writeb(0, &ithc->regs->dma_rx[i].num_prds);
++	}
++	lo_hi_writeq(0, &ithc->regs->dma_tx.addr);
++	writeb(0, &ithc->regs->dma_tx.num_prds);
++
++	ithc_log_regs(ithc);
++	pci_dbg(ithc->pci, "stopped\n");
++}
++
++static void ithc_clear_drvdata(void *res)
++{
++	struct pci_dev *pci = res;
++	pci_set_drvdata(pci, NULL);
++}
++
++static int ithc_start(struct pci_dev *pci)
++{
++	pci_dbg(pci, "starting\n");
++	if (pci_get_drvdata(pci)) {
++		pci_err(pci, "device already initialized\n");
++		return -EINVAL;
++	}
++	if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL))
++		return -ENOMEM;
++
++	// Allocate/init main driver struct.
++	struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL);
++	if (!ithc)
++		return -ENOMEM;
++	ithc->irq = -1;
++	ithc->pci = pci;
++	snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci));
++	pci_set_drvdata(pci, ithc);
++	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci);
++	if (ithc_log_regs_enabled)
++		ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL);
++
++	// PCI initialization.
++	CHECK_RET(pcim_enable_device, pci);
++	pci_set_master(pci);
++	CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs");
++	CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64));
++	CHECK_RET(pci_set_power_state, pci, PCI_D0);
++	ithc->regs = pcim_iomap_table(pci)[0];
++
++	// Allocate IRQ.
++	if (!ithc_use_polling) {
++		CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
++		ithc->irq = CHECK(pci_irq_vector, pci, 0);
++		if (ithc->irq < 0)
++			return ithc->irq;
++	}
++
++	// Initialize THC and touch device.
++	CHECK_RET(ithc_init_device, ithc);
++
++	// Initialize HID and DMA.
++	CHECK_RET(ithc_hid_init, ithc);
++	if (ithc_use_rx0)
++		CHECK_RET(ithc_dma_rx_init, ithc, 0);
++	if (ithc_use_rx1)
++		CHECK_RET(ithc_dma_rx_init, ithc, 1);
++	CHECK_RET(ithc_dma_tx_init, ithc);
++
++	timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0);
++
++	// 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);
++
++	// Start polling/IRQ.
++	if (ithc_use_polling) {
++		pci_info(pci, "using polling instead of irq\n");
++		// Use a thread instead of simple timer because we want to be able to sleep.
++		ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll");
++		if (IS_ERR(ithc->poll_thread)) {
++			int err = PTR_ERR(ithc->poll_thread);
++			ithc->poll_thread = NULL;
++			return err;
++		}
++	} else {
++		CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL,
++			ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc);
++	}
++
++	if (ithc_use_rx0)
++		ithc_dma_rx_enable(ithc, 0);
++	if (ithc_use_rx1)
++		ithc_dma_rx_enable(ithc, 1);
++
++	// 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.dev);
++
++	CHECK(ithc_debug_init_device, ithc);
++
++	ithc_set_ltr_idle(ithc);
++
++	pci_dbg(pci, "started\n");
++	return 0;
++}
++
++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id)
++{
++	pci_dbg(pci, "device probe\n");
++	return ithc_start(pci);
++}
++
++static void ithc_remove(struct pci_dev *pci)
++{
++	pci_dbg(pci, "device remove\n");
++	// all cleanup is handled by devres
++}
++
++// For suspend/resume, we just deinitialize and reinitialize everything.
++// TODO It might be cleaner to keep the HID device around, however we would then have to signal
++// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set
++// feature' requests. Hidraw does not seem to have a facility to do that.
++static int ithc_suspend(struct device *dev)
++{
++	struct pci_dev *pci = to_pci_dev(dev);
++	pci_dbg(pci, "pm suspend\n");
++	devres_release_group(dev, ithc_start);
++	return 0;
++}
++
++static int ithc_resume(struct device *dev)
++{
++	struct pci_dev *pci = to_pci_dev(dev);
++	pci_dbg(pci, "pm resume\n");
++	return ithc_start(pci);
++}
++
++static int ithc_freeze(struct device *dev)
++{
++	struct pci_dev *pci = to_pci_dev(dev);
++	pci_dbg(pci, "pm freeze\n");
++	devres_release_group(dev, ithc_start);
++	return 0;
++}
++
++static int ithc_thaw(struct device *dev)
++{
++	struct pci_dev *pci = to_pci_dev(dev);
++	pci_dbg(pci, "pm thaw\n");
++	return ithc_start(pci);
++}
++
++static int ithc_restore(struct device *dev)
++{
++	struct pci_dev *pci = to_pci_dev(dev);
++	pci_dbg(pci, "pm restore\n");
++	return ithc_start(pci);
++}
++
++static struct pci_driver ithc_driver = {
++	.name = DEVNAME,
++	.id_table = ithc_pci_tbl,
++	.probe = ithc_probe,
++	.remove = ithc_remove,
++	.driver.pm = &(const struct dev_pm_ops) {
++		.suspend = ithc_suspend,
++		.resume = ithc_resume,
++		.freeze = ithc_freeze,
++		.thaw = ithc_thaw,
++		.restore = ithc_restore,
++	},
++	.driver.probe_type = PROBE_PREFER_ASYNCHRONOUS,
++};
++
++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);
++module_exit(ithc_exit);
++
+diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c
+new file mode 100644
+index 000000000000..e2d1690b8cf8
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-quickspi.c
+@@ -0,0 +1,607 @@
++// 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 void set_opcode(struct ithc *ithc, size_t i, u8 opcode)
++{
++	writeb(opcode, &ithc->regs->opcode[i].header);
++	writeb(opcode, &ithc->regs->opcode[i].single);
++	writeb(opcode, &ithc->regs->opcode[i].dual);
++	writeb(opcode, &ithc->regs->opcode[i].quad);
++}
++
++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);
++		writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr);
++	}
++	if (cfg->has_output_report_body_address)
++		writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr);
++
++	switch (ithc->pci->device) {
++	// LKF/TGL don't support QuickSPI.
++	// For ADL, opcode layout is RX/TX/unused.
++	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1:
++	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2:
++	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:
++		if (cfg->has_read_opcode) {
++			set_opcode(ithc, 0, cfg->read_opcode);
++		}
++		if (cfg->has_write_opcode) {
++			set_opcode(ithc, 1, cfg->write_opcode);
++		}
++		break;
++	// For MTL, opcode layout was changed to RX/RX/TX.
++	// (RPL layout is unknown.)
++	default:
++		if (cfg->has_read_opcode) {
++			set_opcode(ithc, 0, cfg->read_opcode);
++			set_opcode(ithc, 1, cfg->read_opcode);
++		}
++		if (cfg->has_write_opcode) {
++			set_opcode(ithc, 2, cfg->write_opcode);
++		}
++		break;
++	}
++
++	ithc_log_regs(ithc);
++
++	// The rest...
++	bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31);
++
++	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
+new file mode 100644
+index 000000000000..c0f13506af20
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-regs.c
+@@ -0,0 +1,154 @@
++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
++
++#include "ithc.h"
++
++#define reg_num(r) (0x1fff & (u16)(__force u64)(r))
++
++void bitsl(__iomem u32 *reg, u32 mask, u32 val)
++{
++	if (val & ~mask)
++		pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n",
++			reg_num(reg), val, mask);
++	writel((readl(reg) & ~mask) | (val & mask), reg);
++}
++
++void bitsb(__iomem u8 *reg, u8 mask, u8 val)
++{
++	if (val & ~mask)
++		pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n",
++			reg_num(reg), val, mask);
++	writeb((readb(reg) & ~mask) | (val & mask), reg);
++}
++
++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;
++}
++
++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale)
++{
++	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_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 0x%x\n", command, size, offset);
++	if (size > sizeof(ithc->regs->spi_cmd.data))
++		return -EINVAL;
++
++	// Wait if the device is still busy.
++	CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0);
++	// Clear result flags.
++	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
++
++	// Init SPI command data.
++	writeb(command, &ithc->regs->spi_cmd.code);
++	writew(size, &ithc->regs->spi_cmd.size);
++	writel(offset, &ithc->regs->spi_cmd.offset);
++	u32 *p = data, n = (size + 3) / 4;
++	for (u32 i = 0; i < n; i++)
++		writel(p[i], &ithc->regs->spi_cmd.data[i]);
++
++	// Start transmission.
++	bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND);
++	CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0);
++
++	// Read response.
++	if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE)
++		return -EIO;
++	if (readw(&ithc->regs->spi_cmd.size) != size)
++		return -EMSGSIZE;
++	for (u32 i = 0; i < n; i++)
++		p[i] = readl(&ithc->regs->spi_cmd.data[i]);
++
++	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
++	return 0;
++}
++
+diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h
+new file mode 100644
+index 000000000000..4f541fe533fa
+--- /dev/null
++++ b/drivers/hid/ithc/ithc-regs.h
+@@ -0,0 +1,211 @@
++/* 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_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
++#define ERROR_CONTROL_UNKNOWN_2             BIT(2)
++#define ERROR_CONTROL_UNKNOWN_3             BIT(3)
++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9     BIT(9)
++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10    BIT(10)
++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12    BIT(12)
++#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13    BIT(13)
++#define ERROR_CONTROL_UNKNOWN_16(x)         (((x) & 0xff) << 16) // spi error code irq?
++#define ERROR_CONTROL_SET_DMA_STATUS        BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs
++
++#define ERROR_STATUS_DMA                    BIT(28)
++#define ERROR_STATUS_SPI                    BIT(30)
++
++#define ERROR_FLAG_DMA_UNKNOWN_9            BIT(9)
++#define ERROR_FLAG_DMA_UNKNOWN_10           BIT(10)
++#define ERROR_FLAG_DMA_RX_TIMEOUT           BIT(12) // set when we receive a truncated DMA message
++#define ERROR_FLAG_DMA_UNKNOWN_13           BIT(13)
++#define ERROR_FLAG_SPI_BUS_TURNAROUND       BIT(16)
++#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT     BIT(17)
++#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18)
++#define ERROR_FLAG_SPI_INVALID_RESPONSE     BIT(19)
++#define ERROR_FLAG_SPI_HS_RX_TIMEOUT        BIT(20)
++#define ERROR_FLAG_SPI_TOUCH_IC_INIT        BIT(21)
++
++#define SPI_CMD_CONTROL_SEND                BIT(0) // cleared by device when sending is complete
++#define SPI_CMD_CONTROL_IRQ                 BIT(1)
++
++#define SPI_CMD_CODE_READ                   4
++#define SPI_CMD_CODE_WRITE                  6
++
++#define SPI_CMD_STATUS_DONE                 BIT(0)
++#define SPI_CMD_STATUS_ERROR                BIT(1)
++#define SPI_CMD_STATUS_BUSY                 BIT(3)
++
++#define DMA_TX_CONTROL_SEND                 BIT(0) // cleared by device when sending is complete
++#define DMA_TX_CONTROL_IRQ                  BIT(3)
++
++#define DMA_TX_STATUS_DONE                  BIT(0)
++#define DMA_TX_STATUS_ERROR                 BIT(1)
++#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_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_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[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;
++	struct {
++		/* 1014/1018/101c */ u8 header;
++		/* 1015/1019/101d */ u8 quad;
++		/* 1016/101a/101e */ u8 dual;
++		/* 1017/101b/101f */ u8 single;
++	} opcode[3];
++	/* 1020 */ u32 error_control;
++	/* 1024 */ u32 error_status; // write to clear
++	/* 1028 */ u32 error_flags; // write to clear
++	/* 102c */ u32 _unknown_102c[5];
++	struct {
++		/* 1040 */ u8 control;
++		/* 1041 */ u8 code;
++		/* 1042 */ u16 size;
++		/* 1044 */ u32 status; // write to clear
++		/* 1048 */ u32 offset;
++		/* 104c */ u32 data[16];
++		/* 108c */ u32 _unknown_108c;
++	} spi_cmd;
++	struct {
++		/* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq()
++		/* 1098 */ u8 control;
++		/* 1099 */ u8 _unknown_1099;
++		/* 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;
++	/* 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 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;
++		/* 1109/1209 */ u8 num_prds;
++		/* 110a/120a */ u16 _unknown_110a;
++		/* 110c/120c */ u8 control;
++		/* 110d/120d */ u8 head;
++		/* 110e/120e */ u8 tail;
++		/* 110f/120f */ u8 control2;
++		/* 1110/1210 */ u32 status; // write to clear
++		/* 1114/1214 */ u32 _unknown_1114;
++		/* 1118/1218 */ u64 _unknown_1118_guc_addr;
++		/* 1120/1220 */ u32 _unknown_1120_guc;
++		/* 1124/1224 */ u32 _unknown_1124_guc;
++		/* 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[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);
++
++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);
++
++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
+new file mode 100644
+index 000000000000..aec320d4e945
+--- /dev/null
++++ b/drivers/hid/ithc/ithc.h
+@@ -0,0 +1,89 @@
++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
++
++#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/input.h>
++#include <linux/io-64-nonatomic-lo-hi.h>
++#include <linux/iopoll.h>
++#include <linux/kthread.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/poll.h>
++#include <linux/timer.h>
++#include <linux/vmalloc.h>
++
++#define DEVNAME "ithc"
++#define DEVFULLNAME "Intel Touch Host Controller"
++
++#undef pr_fmt
++#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++
++#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; })
++#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0)
++
++#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_S_PORT1  0x7f59
++#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2  0x7f5b
++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49
++#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b
++
++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];
++	struct pci_dev *pci;
++	int irq;
++	struct task_struct *poll_thread;
++	struct timer_list idle_timer;
++
++	struct ithc_registers __iomem *regs;
++	struct ithc_registers *prev_regs; // for debugging
++	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);
++
+-- 
+2.48.1
+

+ 2 - 2
patches/6.13/0007-surface-sam.patch

@@ -1,4 +1,4 @@
-From 3029ed9429cdd6e7af835a2cbdb0e339d445a3ad Mon Sep 17 00:00:00 2001
+From f380056e3a34dd28350a41869034943fe78d0041 Mon Sep 17 00:00:00 2001
 From: Lukas <lukas.hetzenecker@gmail.com>
 Date: Sat, 8 Mar 2025 22:00:46 +0100
 Subject: [PATCH] platform/surface: aggregator_registry: Add support for
@@ -38,7 +38,7 @@ index d4f32ad66530..08b4ef382fab 100644
 -- 
 2.48.1
 
-From 6c57c2b436568f430841b64730f64e130d935b85 Mon Sep 17 00:00:00 2001
+From 0fb14f0e1961e47fed10351be0793d44708ea3ad Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Fri, 17 Jun 2022 02:14:00 +0200
 Subject: [PATCH] rtc: Add basic support for RTC via Surface System Aggregator

+ 0 - 2730
patches/6.13/0008-ithc.patch

@@ -1,2730 +0,0 @@
-From f41db8abb594f79d041c4a8374ef3a4c771352de Mon Sep 17 00:00:00 2001
-From: quo <tuple@list.ru>
-Date: Sun, 11 Dec 2022 12:10:54 +0100
-Subject: [PATCH] hid: Add support for Intel Touch Host Controller
-
-Based on quo/ithc-linux@34539af4726d.
-
-Signed-off-by: Maximilian Stoll <luzmaximilian@gmail.com>
-Patchset: ithc
----
- drivers/hid/Kconfig              |   2 +
- drivers/hid/Makefile             |   1 +
- drivers/hid/ithc/Kbuild          |   6 +
- drivers/hid/ithc/Kconfig         |  12 +
- drivers/hid/ithc/ithc-debug.c    | 149 ++++++++
- drivers/hid/ithc/ithc-debug.h    |   7 +
- drivers/hid/ithc/ithc-dma.c      | 312 ++++++++++++++++
- drivers/hid/ithc/ithc-dma.h      |  47 +++
- drivers/hid/ithc/ithc-hid.c      | 207 +++++++++++
- drivers/hid/ithc/ithc-hid.h      |  32 ++
- drivers/hid/ithc/ithc-legacy.c   | 254 +++++++++++++
- drivers/hid/ithc/ithc-legacy.h   |   8 +
- drivers/hid/ithc/ithc-main.c     | 431 ++++++++++++++++++++++
- drivers/hid/ithc/ithc-quickspi.c | 607 +++++++++++++++++++++++++++++++
- drivers/hid/ithc/ithc-quickspi.h |  39 ++
- drivers/hid/ithc/ithc-regs.c     | 154 ++++++++
- drivers/hid/ithc/ithc-regs.h     | 211 +++++++++++
- drivers/hid/ithc/ithc.h          |  89 +++++
- 18 files changed, 2568 insertions(+)
- create mode 100644 drivers/hid/ithc/Kbuild
- create mode 100644 drivers/hid/ithc/Kconfig
- create mode 100644 drivers/hid/ithc/ithc-debug.c
- create mode 100644 drivers/hid/ithc/ithc-debug.h
- create mode 100644 drivers/hid/ithc/ithc-dma.c
- create mode 100644 drivers/hid/ithc/ithc-dma.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-main.c
- create mode 100644 drivers/hid/ithc/ithc-quickspi.c
- create mode 100644 drivers/hid/ithc/ithc-quickspi.h
- create mode 100644 drivers/hid/ithc/ithc-regs.c
- create mode 100644 drivers/hid/ithc/ithc-regs.h
- create mode 100644 drivers/hid/ithc/ithc.h
-
-diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index ce8e61de72c7..db6665977a32 100644
---- a/drivers/hid/Kconfig
-+++ b/drivers/hid/Kconfig
-@@ -1388,4 +1388,6 @@ source "drivers/hid/surface-hid/Kconfig"
- 
- source "drivers/hid/ipts/Kconfig"
- 
-+source "drivers/hid/ithc/Kconfig"
-+
- endif # HID_SUPPORT
-diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index c33ea76797a7..6a89c1eb1b19 100644
---- a/drivers/hid/Makefile
-+++ b/drivers/hid/Makefile
-@@ -173,3 +173,4 @@ obj-$(CONFIG_AMD_SFH_HID)       += amd-sfh-hid/
- obj-$(CONFIG_SURFACE_HID_CORE)  += surface-hid/
- 
- obj-$(CONFIG_HID_IPTS)          += ipts/
-+obj-$(CONFIG_HID_ITHC)          += ithc/
-diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild
-new file mode 100644
-index 000000000000..4937ba131297
---- /dev/null
-+++ b/drivers/hid/ithc/Kbuild
-@@ -0,0 +1,6 @@
-+obj-$(CONFIG_HID_ITHC) := ithc.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/Kconfig b/drivers/hid/ithc/Kconfig
-new file mode 100644
-index 000000000000..ede713023609
---- /dev/null
-+++ b/drivers/hid/ithc/Kconfig
-@@ -0,0 +1,12 @@
-+config HID_ITHC
-+	tristate "Intel Touch Host Controller"
-+	depends on PCI
-+	depends on HID
-+	help
-+	  Say Y here if your system has a touchscreen using Intels
-+	  Touch Host Controller (ITHC / IPTS) technology.
-+
-+	  If unsure say N.
-+
-+	  To compile this driver as a module, choose M here: the
-+	  module will be called ithc.
-diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c
-new file mode 100644
-index 000000000000..2d8c6afe9966
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-debug.c
-@@ -0,0 +1,149 @@
-+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-+
-+#include "ithc.h"
-+
-+void ithc_log_regs(struct ithc *ithc)
-+{
-+	if (!ithc->prev_regs)
-+		return;
-+	u32 __iomem *cur = (__iomem void *)ithc->regs;
-+	u32 *prev = (void *)ithc->prev_regs;
-+	for (int i = 1024; i < sizeof(*ithc->regs) / 4; i++) {
-+		u32 x = readl(cur + i);
-+		if (x != prev[i]) {
-+			pci_info(ithc->pci, "reg %04x: %08x -> %08x\n", i * 4, prev[i], x);
-+			prev[i] = x;
-+		}
-+	}
-+}
-+
-+static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len,
-+	loff_t *offset)
-+{
-+	// Debug commands consist of a single letter followed by a list of numbers (decimal or
-+	// hexadecimal, space-separated).
-+	struct ithc *ithc = file_inode(f)->i_private;
-+	char cmd[256];
-+	if (!ithc || !ithc->pci)
-+		return -ENODEV;
-+	if (!len)
-+		return -EINVAL;
-+	if (len >= sizeof(cmd))
-+		return -EINVAL;
-+	if (copy_from_user(cmd, buf, len))
-+		return -EFAULT;
-+	cmd[len] = 0;
-+	if (cmd[len-1] == '\n')
-+		cmd[len-1] = 0;
-+	pci_info(ithc->pci, "debug command: %s\n", cmd);
-+
-+	// Parse the list of arguments into a u32 array.
-+	u32 n = 0;
-+	const char *s = cmd + 1;
-+	u32 a[32];
-+	while (*s && *s != '\n') {
-+		if (n >= ARRAY_SIZE(a))
-+			return -EINVAL;
-+		if (*s++ != ' ')
-+			return -EINVAL;
-+		char *e;
-+		a[n++] = simple_strtoul(s, &e, 0);
-+		if (e == s)
-+			return -EINVAL;
-+		s = e;
-+	}
-+	ithc_log_regs(ithc);
-+
-+	// Execute the command.
-+	switch (cmd[0]) {
-+	case 'x': // reset
-+		ithc_reset(ithc);
-+		break;
-+	case 'w': // write register: offset mask value
-+		if (n != 3 || (a[0] & 3))
-+			return -EINVAL;
-+		pci_info(ithc->pci, "debug write 0x%04x = 0x%08x (mask 0x%08x)\n",
-+			a[0], a[2], a[1]);
-+		bitsl(((__iomem u32 *)ithc->regs) + a[0] / 4, a[1], a[2]);
-+		break;
-+	case 'r': // read register: offset
-+		if (n != 1 || (a[0] & 3))
-+			return -EINVAL;
-+		pci_info(ithc->pci, "debug read 0x%04x = 0x%08x\n", a[0],
-+			readl(((__iomem u32 *)ithc->regs) + a[0] / 4));
-+		break;
-+	case 's': // spi command: cmd offset len data...
-+		// read config: s 4 0 64 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-+		// set touch cfg: s 6 12 4 XX
-+		if (n < 3 || a[2] > (n - 3) * 4)
-+			return -EINVAL;
-+		pci_info(ithc->pci, "debug spi command %u with %u bytes of data\n", a[0], a[2]);
-+		if (!CHECK(ithc_spi_command, ithc, a[0], a[1], a[2], a + 3))
-+			for (u32 i = 0; i < (a[2] + 3) / 4; i++)
-+				pci_info(ithc->pci, "resp %u = 0x%08x\n", i, a[3+i]);
-+		break;
-+	case 'd': // dma command: cmd len data...
-+		// get report descriptor: d 7 8 0 0
-+		// enable multitouch: d 3 2 0x0105
-+		if (n < 1)
-+			return -EINVAL;
-+		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:
-+		return -EINVAL;
-+	}
-+	ithc_log_regs(ithc);
-+	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,
-+};
-+
-+static void ithc_debugfs_devres_release(struct device *dev, void *res)
-+{
-+	struct dentry **dbgm = res;
-+	debugfs_remove_recursive(*dbgm);
-+}
-+
-+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(pci_name(ithc->pci), dbg_dir);
-+	if (IS_ERR(dbg))
-+		return PTR_ERR(dbg);
-+	*dbgm = dbg;
-+
-+	struct dentry *cmd = debugfs_create_file("cmd", 0220, dbg, ithc, &ithc_debugfops_cmd);
-+	if (IS_ERR(cmd))
-+		return PTR_ERR(cmd);
-+
-+	return 0;
-+}
-+
-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
-new file mode 100644
-index 000000000000..bf4eab33062b
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-dma.c
-@@ -0,0 +1,312 @@
-+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-+
-+#include "ithc.h"
-+
-+// The THC uses tables of PRDs (physical region descriptors) to describe the TX and RX data buffers.
-+// Each PRD contains the DMA address and size of a block of DMA memory, and some status flags.
-+// This allows each data buffer to consist of multiple non-contiguous blocks of memory.
-+
-+static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p,
-+	unsigned int num_buffers, unsigned int num_pages, enum dma_data_direction dir)
-+{
-+	p->num_pages = num_pages;
-+	p->dir = dir;
-+	// We allocate enough space to have one PRD per data buffer page, however if the data
-+	// buffer pages happen to be contiguous, we can describe the buffer using fewer PRDs, so
-+	// some will remain unused (which is fine).
-+	p->size = round_up(num_buffers * num_pages * sizeof(struct ithc_phys_region_desc), PAGE_SIZE);
-+	p->addr = dmam_alloc_coherent(&ithc->pci->dev, p->size, &p->dma_addr, GFP_KERNEL);
-+	if (!p->addr)
-+		return -ENOMEM;
-+	if (p->dma_addr & (PAGE_SIZE - 1))
-+		return -EFAULT;
-+	return 0;
-+}
-+
-+// Devres managed sg_table wrapper.
-+struct ithc_sg_table {
-+	void *addr;
-+	struct sg_table sgt;
-+	enum dma_data_direction dir;
-+};
-+static void ithc_dma_sgtable_free(struct sg_table *sgt)
-+{
-+	struct scatterlist *sg;
-+	int i;
-+	for_each_sgtable_sg(sgt, sg, i) {
-+		struct page *p = sg_page(sg);
-+		if (p)
-+			__free_page(p);
-+	}
-+	sg_free_table(sgt);
-+}
-+static void ithc_dma_data_devres_release(struct device *dev, void *res)
-+{
-+	struct ithc_sg_table *sgt = res;
-+	if (sgt->addr)
-+		vunmap(sgt->addr);
-+	dma_unmap_sgtable(dev, &sgt->sgt, sgt->dir, 0);
-+	ithc_dma_sgtable_free(&sgt->sgt);
-+}
-+
-+static int ithc_dma_data_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
-+	struct ithc_dma_data_buffer *b)
-+{
-+	// We don't use dma_alloc_coherent() for data buffers, because they don't have to be
-+	// coherent (they are unidirectional) or contiguous (we can use one PRD per page).
-+	// We could use dma_alloc_noncontiguous(), however this still always allocates a single
-+	// DMA mapped segment, which is more restrictive than what we need.
-+	// Instead we use an sg_table of individually allocated pages.
-+	struct page *pages[16];
-+	if (prds->num_pages == 0 || prds->num_pages > ARRAY_SIZE(pages))
-+		return -EINVAL;
-+	b->active_idx = -1;
-+	struct ithc_sg_table *sgt = devres_alloc(
-+		ithc_dma_data_devres_release, sizeof(*sgt), GFP_KERNEL);
-+	if (!sgt)
-+		return -ENOMEM;
-+	sgt->dir = prds->dir;
-+
-+	if (!sg_alloc_table(&sgt->sgt, prds->num_pages, GFP_KERNEL)) {
-+		struct scatterlist *sg;
-+		int i;
-+		bool ok = true;
-+		for_each_sgtable_sg(&sgt->sgt, sg, i) {
-+			// NOTE: don't need __GFP_DMA for PCI DMA
-+			struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
-+			if (!p) {
-+				ok = false;
-+				break;
-+			}
-+			sg_set_page(sg, p, PAGE_SIZE, 0);
-+		}
-+		if (ok && !dma_map_sgtable(&ithc->pci->dev, &sgt->sgt, prds->dir, 0)) {
-+			devres_add(&ithc->pci->dev, sgt);
-+			b->sgt = &sgt->sgt;
-+			b->addr = sgt->addr = vmap(pages, prds->num_pages, 0, PAGE_KERNEL);
-+			if (!b->addr)
-+				return -ENOMEM;
-+			return 0;
-+		}
-+		ithc_dma_sgtable_free(&sgt->sgt);
-+	}
-+	devres_free(sgt);
-+	return -ENOMEM;
-+}
-+
-+static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
-+	struct ithc_dma_data_buffer *b, unsigned int idx)
-+{
-+	// Give a buffer to the THC.
-+	struct ithc_phys_region_desc *prd = prds->addr;
-+	prd += idx * prds->num_pages;
-+	if (b->active_idx >= 0) {
-+		pci_err(ithc->pci, "buffer already active\n");
-+		return -EINVAL;
-+	}
-+	b->active_idx = idx;
-+	if (prds->dir == DMA_TO_DEVICE) {
-+		// TX buffer: Caller should have already filled the data buffer, so just fill
-+		// the PRD and flush.
-+		// (TODO: Support multi-page TX buffers. So far no device seems to use or need
-+		// these though.)
-+		if (b->data_size > PAGE_SIZE)
-+			return -EINVAL;
-+		prd->addr = sg_dma_address(b->sgt->sgl) >> 10;
-+		prd->size = b->data_size | PRD_FLAG_END;
-+		flush_kernel_vmap_range(b->addr, b->data_size);
-+	} else if (prds->dir == DMA_FROM_DEVICE) {
-+		// RX buffer: Reset PRDs.
-+		struct scatterlist *sg;
-+		int i;
-+		for_each_sgtable_dma_sg(b->sgt, sg, i) {
-+			prd->addr = sg_dma_address(sg) >> 10;
-+			prd->size = sg_dma_len(sg);
-+			prd++;
-+		}
-+		prd[-1].size |= PRD_FLAG_END;
-+	}
-+	dma_wmb(); // for the prds
-+	dma_sync_sgtable_for_device(&ithc->pci->dev, b->sgt, prds->dir);
-+	return 0;
-+}
-+
-+static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffer *prds,
-+	struct ithc_dma_data_buffer *b, unsigned int idx)
-+{
-+	// Take a buffer from the THC.
-+	struct ithc_phys_region_desc *prd = prds->addr;
-+	prd += idx * prds->num_pages;
-+	// This is purely a sanity check. We don't strictly need the idx parameter for this
-+	// function, because it should always be the same as active_idx, unless we have a bug.
-+	if (b->active_idx != idx) {
-+		pci_err(ithc->pci, "wrong buffer index\n");
-+		return -EINVAL;
-+	}
-+	b->active_idx = -1;
-+	if (prds->dir == DMA_FROM_DEVICE) {
-+		// RX buffer: Calculate actual received data size from PRDs.
-+		dma_rmb(); // for the prds
-+		b->data_size = 0;
-+		struct scatterlist *sg;
-+		int i;
-+		for_each_sgtable_dma_sg(b->sgt, sg, i) {
-+			unsigned int size = prd->size;
-+			b->data_size += size & PRD_SIZE_MASK;
-+			if (size & PRD_FLAG_END)
-+				break;
-+			if ((size & PRD_SIZE_MASK) != sg_dma_len(sg)) {
-+				pci_err(ithc->pci, "truncated prd\n");
-+				break;
-+			}
-+			prd++;
-+		}
-+		invalidate_kernel_vmap_range(b->addr, b->data_size);
-+	}
-+	dma_sync_sgtable_for_cpu(&ithc->pci->dev, b->sgt, prds->dir);
-+	return 0;
-+}
-+
-+int ithc_dma_rx_init(struct ithc *ithc, u8 channel)
-+{
-+	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
-+	mutex_init(&rx->mutex);
-+
-+	// Allocate buffers.
-+	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, 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]);
-+
-+	// Init registers.
-+	writeb(DMA_RX_CONTROL2_RESET, &ithc->regs->dma_rx[channel].control2);
-+	lo_hi_writeq(rx->prds.dma_addr, &ithc->regs->dma_rx[channel].addr);
-+	writeb(NUM_RX_BUF - 1, &ithc->regs->dma_rx[channel].num_bufs);
-+	writeb(num_pages - 1, &ithc->regs->dma_rx[channel].num_prds);
-+	u8 head = readb(&ithc->regs->dma_rx[channel].head);
-+	if (head) {
-+		pci_err(ithc->pci, "head is nonzero (%u)\n", head);
-+		return -EIO;
-+	}
-+
-+	// Init buffers.
-+	for (unsigned int i = 0; i < NUM_RX_BUF; i++)
-+		CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, &rx->bufs[i], i);
-+
-+	writeb(head ^ DMA_RX_WRAP_FLAG, &ithc->regs->dma_rx[channel].tail);
-+	return 0;
-+}
-+
-+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel)
-+{
-+	bitsb_set(&ithc->regs->dma_rx[channel].control,
-+		DMA_RX_CONTROL_ENABLE | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_DATA);
-+	CHECK(waitl, ithc, &ithc->regs->dma_rx[channel].status,
-+		DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED);
-+}
-+
-+int ithc_dma_tx_init(struct ithc *ithc)
-+{
-+	struct ithc_dma_tx *tx = &ithc->dma_tx;
-+	mutex_init(&tx->mutex);
-+
-+	// Allocate buffers.
-+	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",
-+		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);
-+
-+	// Init registers.
-+	lo_hi_writeq(tx->prds.dma_addr, &ithc->regs->dma_tx.addr);
-+	writeb(num_pages - 1, &ithc->regs->dma_tx.num_prds);
-+
-+	// Init buffers.
-+	CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
-+	return 0;
-+}
-+
-+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
-+{
-+	// Process all filled RX buffers from the ringbuffer.
-+	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
-+	unsigned int n = rx->num_received;
-+	u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head);
-+	while (1) {
-+		u8 tail = n % NUM_RX_BUF;
-+		u8 tail_wrap = tail | ((n / NUM_RX_BUF) & 1 ? 0 : DMA_RX_WRAP_FLAG);
-+		writeb(tail_wrap, &ithc->regs->dma_rx[channel].tail);
-+		// ringbuffer is full if tail_wrap == head_wrap
-+		// ringbuffer is empty if tail_wrap == head_wrap ^ WRAP_FLAG
-+		if (tail_wrap == (head_wrap ^ DMA_RX_WRAP_FLAG))
-+			return 0;
-+
-+		// take the buffer that the device just filled
-+		struct ithc_dma_data_buffer *b = &rx->bufs[n % NUM_RX_BUF];
-+		CHECK_RET(ithc_dma_data_buffer_get, ithc, &rx->prds, b, tail);
-+		rx->num_received = ++n;
-+
-+		// process data
-+		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);
-+	}
-+}
-+int ithc_dma_rx(struct ithc *ithc, u8 channel)
-+{
-+	struct ithc_dma_rx *rx = &ithc->dma_rx[channel];
-+	mutex_lock(&rx->mutex);
-+	int ret = ithc_dma_rx_unlocked(ithc, channel);
-+	mutex_unlock(&rx->mutex);
-+	return ret;
-+}
-+
-+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data)
-+{
-+	// Send a single TX buffer to the THC.
-+	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.
-+	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);
-+	CHECK_RET(waitb, ithc, &ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0);
-+	writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status);
-+	return 0;
-+}
-+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, 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
-new file mode 100644
-index 000000000000..1749a5819b3e
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-dma.h
-@@ -0,0 +1,47 @@
-+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-+
-+#define PRD_SIZE_MASK            0xffffff
-+#define PRD_FLAG_END             0x1000000
-+#define PRD_FLAG_SUCCESS         0x2000000
-+#define PRD_FLAG_ERROR           0x4000000
-+
-+struct ithc_phys_region_desc {
-+	u64 addr; // physical addr/1024
-+	u32 size; // num bytes, PRD_FLAG_END marks last prd for data split over multiple prds
-+	u32 unused;
-+};
-+
-+struct ithc_dma_prd_buffer {
-+	void *addr;
-+	dma_addr_t dma_addr;
-+	u32 size;
-+	u32 num_pages; // per data buffer
-+	enum dma_data_direction dir;
-+};
-+
-+struct ithc_dma_data_buffer {
-+	void *addr;
-+	struct sg_table *sgt;
-+	int active_idx;
-+	u32 data_size;
-+};
-+
-+struct ithc_dma_tx {
-+	struct mutex mutex;
-+	struct ithc_dma_prd_buffer prds;
-+	struct ithc_dma_data_buffer buf;
-+};
-+
-+struct ithc_dma_rx {
-+	struct mutex mutex;
-+	u32 num_received;
-+	struct ithc_dma_prd_buffer prds;
-+	struct ithc_dma_data_buffer bufs[NUM_RX_BUF];
-+};
-+
-+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, 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..8883987fb352
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-legacy.c
-@@ -0,0 +1,254 @@
-+// 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 ADL devices.
-+	switch (ithc->pci->device) {
-+	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1:
-+	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2:
-+	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
-new file mode 100644
-index 000000000000..ac56c253674b
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-main.c
-@@ -0,0 +1,431 @@
-+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-+
-+#include "ithc.h"
-+
-+MODULE_DESCRIPTION("Intel Touch Host Controller driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+static const struct pci_device_id ithc_pci_tbl[] = {
-+	{
-+		.vendor = PCI_VENDOR_ID_INTEL,
-+		.device = PCI_ANY_ID,
-+		.subvendor = PCI_ANY_ID,
-+		.subdevice = PCI_ANY_ID,
-+		.class = PCI_CLASS_INPUT_PEN << 8,
-+		.class_mask = ~0,
-+	},
-+	{}
-+};
-+MODULE_DEVICE_TABLE(pci, ithc_pci_tbl);
-+
-+// Module parameters
-+
-+static bool ithc_use_polling = false;
-+module_param_named(poll, ithc_use_polling, bool, 0);
-+MODULE_PARM_DESC(poll, "Use polling instead of interrupts");
-+
-+// Since all known devices seem to use only channel 1, by default we disable channel 0.
-+static bool ithc_use_rx0 = false;
-+module_param_named(rx0, ithc_use_rx0, bool, 0);
-+MODULE_PARM_DESC(rx0, "Use DMA RX channel 0");
-+
-+static bool ithc_use_rx1 = true;
-+module_param_named(rx1, ithc_use_rx1, bool, 0);
-+MODULE_PARM_DESC(rx1, "Use DMA RX channel 1");
-+
-+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)");
-+
-+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 unsigned int ithc_idle_delay_ms = 1000;
-+module_param_named(idledelay, ithc_idle_delay_ms, uint, 0);
-+MODULE_PARM_DESC(idleltr, "Minimum idle time before applying idle LTR value (in milliseconds)");
-+
-+static bool ithc_log_regs_enabled = false;
-+module_param_named(logregs, ithc_log_regs_enabled, bool, 0);
-+MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)");
-+
-+// Interrupts/polling
-+
-+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_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_READY | DMA_RX_STATUS_HAVE_DATA,
-+		&ithc->regs->dma_rx[channel].status);
-+}
-+
-+static void ithc_clear_interrupts(struct ithc *ithc)
-+{
-+	writel(0xffffffff, &ithc->regs->error_flags);
-+	writel(ERROR_STATUS_DMA | ERROR_STATUS_SPI, &ithc->regs->error_status);
-+	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
-+	ithc_clear_dma_rx_interrupts(ithc, 0);
-+	ithc_clear_dma_rx_interrupts(ithc, 1);
-+	writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2,
-+		&ithc->regs->dma_tx.status);
-+}
-+
-+static void ithc_idle_timer_callback(struct timer_list *t)
-+{
-+	struct ithc *ithc = container_of(t, struct ithc, idle_timer);
-+	ithc_set_ltr_idle(ithc);
-+}
-+
-+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 after a delay.
-+	mod_timer(&ithc->idle_timer, jiffies + msecs_to_jiffies(ithc_idle_delay_ms));
-+
-+	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;
-+
-+	// 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)
-+			pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n");
-+	}
-+
-+	// Process DMA rx
-+	if (ithc_use_rx0) {
-+		ithc_clear_dma_rx_interrupts(ithc, 0);
-+		if (rx0)
-+			ithc_dma_rx(ithc, 0);
-+	}
-+	if (ithc_use_rx1) {
-+		ithc_clear_dma_rx_interrupts(ithc, 1);
-+		if (rx1)
-+			ithc_dma_rx(ithc, 1);
-+	}
-+
-+	ithc_log_regs(ithc);
-+}
-+
-+static irqreturn_t ithc_interrupt_thread(int irq, void *arg)
-+{
-+	struct ithc *ithc = arg;
-+	pci_dbg(ithc->pci, "IRQ! err=%08x/%08x/%08x, cmd=%02x/%08x, rx0=%02x/%08x, rx1=%02x/%08x, tx=%02x/%08x\n",
-+		readl(&ithc->regs->error_control), readl(&ithc->regs->error_status), readl(&ithc->regs->error_flags),
-+		readb(&ithc->regs->spi_cmd.control), readl(&ithc->regs->spi_cmd.status),
-+		readb(&ithc->regs->dma_rx[0].control), readl(&ithc->regs->dma_rx[0].status),
-+		readb(&ithc->regs->dma_rx[1].control), readl(&ithc->regs->dma_rx[1].status),
-+		readb(&ithc->regs->dma_tx.control), readl(&ithc->regs->dma_tx.status));
-+	ithc_process(ithc);
-+	return IRQ_HANDLED;
-+}
-+
-+static int ithc_poll_thread(void *arg)
-+{
-+	struct ithc *ithc = arg;
-+	unsigned int sleep = 100;
-+	while (!kthread_should_stop()) {
-+		u32 n = ithc->dma_rx[1].num_received;
-+		ithc_process(ithc);
-+		// Decrease polling interval to 20ms if we received data, otherwise slowly
-+		// increase it up to 200ms.
-+		sleep = n != ithc->dma_rx[1].num_received ? 20
-+			: min(200u, sleep + (sleep >> 4) + 1);
-+		msleep_interruptible(sleep);
-+	}
-+	return 0;
-+}
-+
-+// Device initialization and shutdown
-+
-+static void ithc_disable(struct ithc *ithc)
-+{
-+	bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE);
-+	CHECK(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED);
-+	bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
-+	bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND, 0);
-+	bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND, 0);
-+	bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_ENABLE, 0);
-+	bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_ENABLE, 0);
-+	ithc_disable_interrupts(ithc);
-+	ithc_clear_interrupts(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);
-+	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;
-+
-+	// 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 50us, 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
-+		: 50 * 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);
-+
-+	return 0;
-+}
-+
-+int ithc_reset(struct ithc *ithc)
-+{
-+	// FIXME This should probably do devres_release_group()+ithc_start().
-+	// But because this is called during DMA processing, that would have to be done
-+	// asynchronously (schedule_work()?). And with extra locking?
-+	pci_err(ithc->pci, "reset\n");
-+	CHECK(ithc_init_device, ithc);
-+	if (ithc_use_rx0)
-+		ithc_dma_rx_enable(ithc, 0);
-+	if (ithc_use_rx1)
-+		ithc_dma_rx_enable(ithc, 1);
-+	ithc_log_regs(ithc);
-+	pci_dbg(ithc->pci, "reset completed\n");
-+	return 0;
-+}
-+
-+static void ithc_stop(void *res)
-+{
-+	struct ithc *ithc = res;
-+	pci_dbg(ithc->pci, "stopping\n");
-+	ithc_log_regs(ithc);
-+
-+	if (ithc->poll_thread)
-+		CHECK(kthread_stop, ithc->poll_thread);
-+	if (ithc->irq >= 0)
-+		disable_irq(ithc->irq);
-+	if (ithc->use_quickspi)
-+		ithc_quickspi_exit(ithc);
-+	else
-+		ithc_legacy_exit(ithc);
-+	ithc_disable(ithc);
-+	del_timer_sync(&ithc->idle_timer);
-+
-+	// Clear DMA config.
-+	for (unsigned int i = 0; i < 2; i++) {
-+		CHECK(waitl, ithc, &ithc->regs->dma_rx[i].status, DMA_RX_STATUS_ENABLED, 0);
-+		lo_hi_writeq(0, &ithc->regs->dma_rx[i].addr);
-+		writeb(0, &ithc->regs->dma_rx[i].num_bufs);
-+		writeb(0, &ithc->regs->dma_rx[i].num_prds);
-+	}
-+	lo_hi_writeq(0, &ithc->regs->dma_tx.addr);
-+	writeb(0, &ithc->regs->dma_tx.num_prds);
-+
-+	ithc_log_regs(ithc);
-+	pci_dbg(ithc->pci, "stopped\n");
-+}
-+
-+static void ithc_clear_drvdata(void *res)
-+{
-+	struct pci_dev *pci = res;
-+	pci_set_drvdata(pci, NULL);
-+}
-+
-+static int ithc_start(struct pci_dev *pci)
-+{
-+	pci_dbg(pci, "starting\n");
-+	if (pci_get_drvdata(pci)) {
-+		pci_err(pci, "device already initialized\n");
-+		return -EINVAL;
-+	}
-+	if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL))
-+		return -ENOMEM;
-+
-+	// Allocate/init main driver struct.
-+	struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof(*ithc), GFP_KERNEL);
-+	if (!ithc)
-+		return -ENOMEM;
-+	ithc->irq = -1;
-+	ithc->pci = pci;
-+	snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci));
-+	pci_set_drvdata(pci, ithc);
-+	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci);
-+	if (ithc_log_regs_enabled)
-+		ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof(*ithc->prev_regs), GFP_KERNEL);
-+
-+	// PCI initialization.
-+	CHECK_RET(pcim_enable_device, pci);
-+	pci_set_master(pci);
-+	CHECK_RET(pcim_iomap_regions, pci, BIT(0), DEVNAME " regs");
-+	CHECK_RET(dma_set_mask_and_coherent, &pci->dev, DMA_BIT_MASK(64));
-+	CHECK_RET(pci_set_power_state, pci, PCI_D0);
-+	ithc->regs = pcim_iomap_table(pci)[0];
-+
-+	// Allocate IRQ.
-+	if (!ithc_use_polling) {
-+		CHECK_RET(pci_alloc_irq_vectors, pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_MSIX);
-+		ithc->irq = CHECK(pci_irq_vector, pci, 0);
-+		if (ithc->irq < 0)
-+			return ithc->irq;
-+	}
-+
-+	// Initialize THC and touch device.
-+	CHECK_RET(ithc_init_device, ithc);
-+
-+	// Initialize HID and DMA.
-+	CHECK_RET(ithc_hid_init, ithc);
-+	if (ithc_use_rx0)
-+		CHECK_RET(ithc_dma_rx_init, ithc, 0);
-+	if (ithc_use_rx1)
-+		CHECK_RET(ithc_dma_rx_init, ithc, 1);
-+	CHECK_RET(ithc_dma_tx_init, ithc);
-+
-+	timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0);
-+
-+	// 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);
-+
-+	// Start polling/IRQ.
-+	if (ithc_use_polling) {
-+		pci_info(pci, "using polling instead of irq\n");
-+		// Use a thread instead of simple timer because we want to be able to sleep.
-+		ithc->poll_thread = kthread_run(ithc_poll_thread, ithc, DEVNAME "poll");
-+		if (IS_ERR(ithc->poll_thread)) {
-+			int err = PTR_ERR(ithc->poll_thread);
-+			ithc->poll_thread = NULL;
-+			return err;
-+		}
-+	} else {
-+		CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL,
-+			ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc);
-+	}
-+
-+	if (ithc_use_rx0)
-+		ithc_dma_rx_enable(ithc, 0);
-+	if (ithc_use_rx1)
-+		ithc_dma_rx_enable(ithc, 1);
-+
-+	// 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.dev);
-+
-+	CHECK(ithc_debug_init_device, ithc);
-+
-+	ithc_set_ltr_idle(ithc);
-+
-+	pci_dbg(pci, "started\n");
-+	return 0;
-+}
-+
-+static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id)
-+{
-+	pci_dbg(pci, "device probe\n");
-+	return ithc_start(pci);
-+}
-+
-+static void ithc_remove(struct pci_dev *pci)
-+{
-+	pci_dbg(pci, "device remove\n");
-+	// all cleanup is handled by devres
-+}
-+
-+// For suspend/resume, we just deinitialize and reinitialize everything.
-+// TODO It might be cleaner to keep the HID device around, however we would then have to signal
-+// to userspace that the touch device has lost state and userspace needs to e.g. resend 'set
-+// feature' requests. Hidraw does not seem to have a facility to do that.
-+static int ithc_suspend(struct device *dev)
-+{
-+	struct pci_dev *pci = to_pci_dev(dev);
-+	pci_dbg(pci, "pm suspend\n");
-+	devres_release_group(dev, ithc_start);
-+	return 0;
-+}
-+
-+static int ithc_resume(struct device *dev)
-+{
-+	struct pci_dev *pci = to_pci_dev(dev);
-+	pci_dbg(pci, "pm resume\n");
-+	return ithc_start(pci);
-+}
-+
-+static int ithc_freeze(struct device *dev)
-+{
-+	struct pci_dev *pci = to_pci_dev(dev);
-+	pci_dbg(pci, "pm freeze\n");
-+	devres_release_group(dev, ithc_start);
-+	return 0;
-+}
-+
-+static int ithc_thaw(struct device *dev)
-+{
-+	struct pci_dev *pci = to_pci_dev(dev);
-+	pci_dbg(pci, "pm thaw\n");
-+	return ithc_start(pci);
-+}
-+
-+static int ithc_restore(struct device *dev)
-+{
-+	struct pci_dev *pci = to_pci_dev(dev);
-+	pci_dbg(pci, "pm restore\n");
-+	return ithc_start(pci);
-+}
-+
-+static struct pci_driver ithc_driver = {
-+	.name = DEVNAME,
-+	.id_table = ithc_pci_tbl,
-+	.probe = ithc_probe,
-+	.remove = ithc_remove,
-+	.driver.pm = &(const struct dev_pm_ops) {
-+		.suspend = ithc_suspend,
-+		.resume = ithc_resume,
-+		.freeze = ithc_freeze,
-+		.thaw = ithc_thaw,
-+		.restore = ithc_restore,
-+	},
-+	.driver.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-+};
-+
-+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);
-+module_exit(ithc_exit);
-+
-diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c
-new file mode 100644
-index 000000000000..e2d1690b8cf8
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-quickspi.c
-@@ -0,0 +1,607 @@
-+// 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 void set_opcode(struct ithc *ithc, size_t i, u8 opcode)
-+{
-+	writeb(opcode, &ithc->regs->opcode[i].header);
-+	writeb(opcode, &ithc->regs->opcode[i].single);
-+	writeb(opcode, &ithc->regs->opcode[i].dual);
-+	writeb(opcode, &ithc->regs->opcode[i].quad);
-+}
-+
-+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);
-+		writel(cfg->input_report_body_address, &ithc->regs->dma_rx[1].spi_addr);
-+	}
-+	if (cfg->has_output_report_body_address)
-+		writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr);
-+
-+	switch (ithc->pci->device) {
-+	// LKF/TGL don't support QuickSPI.
-+	// For ADL, opcode layout is RX/TX/unused.
-+	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1:
-+	case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2:
-+	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:
-+		if (cfg->has_read_opcode) {
-+			set_opcode(ithc, 0, cfg->read_opcode);
-+		}
-+		if (cfg->has_write_opcode) {
-+			set_opcode(ithc, 1, cfg->write_opcode);
-+		}
-+		break;
-+	// For MTL, opcode layout was changed to RX/RX/TX.
-+	// (RPL layout is unknown.)
-+	default:
-+		if (cfg->has_read_opcode) {
-+			set_opcode(ithc, 0, cfg->read_opcode);
-+			set_opcode(ithc, 1, cfg->read_opcode);
-+		}
-+		if (cfg->has_write_opcode) {
-+			set_opcode(ithc, 2, cfg->write_opcode);
-+		}
-+		break;
-+	}
-+
-+	ithc_log_regs(ithc);
-+
-+	// The rest...
-+	bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31);
-+
-+	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
-new file mode 100644
-index 000000000000..c0f13506af20
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-regs.c
-@@ -0,0 +1,154 @@
-+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
-+
-+#include "ithc.h"
-+
-+#define reg_num(r) (0x1fff & (u16)(__force u64)(r))
-+
-+void bitsl(__iomem u32 *reg, u32 mask, u32 val)
-+{
-+	if (val & ~mask)
-+		pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n",
-+			reg_num(reg), val, mask);
-+	writel((readl(reg) & ~mask) | (val & mask), reg);
-+}
-+
-+void bitsb(__iomem u8 *reg, u8 mask, u8 val)
-+{
-+	if (val & ~mask)
-+		pr_err("register 0x%x: invalid value 0x%x for bitmask 0x%x\n",
-+			reg_num(reg), val, mask);
-+	writeb((readb(reg) & ~mask) | (val & mask), reg);
-+}
-+
-+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;
-+}
-+
-+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale)
-+{
-+	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_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 0x%x\n", command, size, offset);
-+	if (size > sizeof(ithc->regs->spi_cmd.data))
-+		return -EINVAL;
-+
-+	// Wait if the device is still busy.
-+	CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0);
-+	// Clear result flags.
-+	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
-+
-+	// Init SPI command data.
-+	writeb(command, &ithc->regs->spi_cmd.code);
-+	writew(size, &ithc->regs->spi_cmd.size);
-+	writel(offset, &ithc->regs->spi_cmd.offset);
-+	u32 *p = data, n = (size + 3) / 4;
-+	for (u32 i = 0; i < n; i++)
-+		writel(p[i], &ithc->regs->spi_cmd.data[i]);
-+
-+	// Start transmission.
-+	bitsb_set(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_SEND);
-+	CHECK_RET(waitl, ithc, &ithc->regs->spi_cmd.status, SPI_CMD_STATUS_BUSY, 0);
-+
-+	// Read response.
-+	if ((readl(&ithc->regs->spi_cmd.status) & (SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR)) != SPI_CMD_STATUS_DONE)
-+		return -EIO;
-+	if (readw(&ithc->regs->spi_cmd.size) != size)
-+		return -EMSGSIZE;
-+	for (u32 i = 0; i < n; i++)
-+		p[i] = readl(&ithc->regs->spi_cmd.data[i]);
-+
-+	writel(SPI_CMD_STATUS_DONE | SPI_CMD_STATUS_ERROR, &ithc->regs->spi_cmd.status);
-+	return 0;
-+}
-+
-diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h
-new file mode 100644
-index 000000000000..4f541fe533fa
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-regs.h
-@@ -0,0 +1,211 @@
-+/* 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_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
-+#define ERROR_CONTROL_UNKNOWN_2             BIT(2)
-+#define ERROR_CONTROL_UNKNOWN_3             BIT(3)
-+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_9     BIT(9)
-+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_10    BIT(10)
-+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_12    BIT(12)
-+#define ERROR_CONTROL_IRQ_DMA_UNKNOWN_13    BIT(13)
-+#define ERROR_CONTROL_UNKNOWN_16(x)         (((x) & 0xff) << 16) // spi error code irq?
-+#define ERROR_CONTROL_SET_DMA_STATUS        BIT(29) // sets DMA_RX_STATUS_ERROR when a DMA error occurs
-+
-+#define ERROR_STATUS_DMA                    BIT(28)
-+#define ERROR_STATUS_SPI                    BIT(30)
-+
-+#define ERROR_FLAG_DMA_UNKNOWN_9            BIT(9)
-+#define ERROR_FLAG_DMA_UNKNOWN_10           BIT(10)
-+#define ERROR_FLAG_DMA_RX_TIMEOUT           BIT(12) // set when we receive a truncated DMA message
-+#define ERROR_FLAG_DMA_UNKNOWN_13           BIT(13)
-+#define ERROR_FLAG_SPI_BUS_TURNAROUND       BIT(16)
-+#define ERROR_FLAG_SPI_RESPONSE_TIMEOUT     BIT(17)
-+#define ERROR_FLAG_SPI_INTRA_PACKET_TIMEOUT BIT(18)
-+#define ERROR_FLAG_SPI_INVALID_RESPONSE     BIT(19)
-+#define ERROR_FLAG_SPI_HS_RX_TIMEOUT        BIT(20)
-+#define ERROR_FLAG_SPI_TOUCH_IC_INIT        BIT(21)
-+
-+#define SPI_CMD_CONTROL_SEND                BIT(0) // cleared by device when sending is complete
-+#define SPI_CMD_CONTROL_IRQ                 BIT(1)
-+
-+#define SPI_CMD_CODE_READ                   4
-+#define SPI_CMD_CODE_WRITE                  6
-+
-+#define SPI_CMD_STATUS_DONE                 BIT(0)
-+#define SPI_CMD_STATUS_ERROR                BIT(1)
-+#define SPI_CMD_STATUS_BUSY                 BIT(3)
-+
-+#define DMA_TX_CONTROL_SEND                 BIT(0) // cleared by device when sending is complete
-+#define DMA_TX_CONTROL_IRQ                  BIT(3)
-+
-+#define DMA_TX_STATUS_DONE                  BIT(0)
-+#define DMA_TX_STATUS_ERROR                 BIT(1)
-+#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_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_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[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;
-+	struct {
-+		/* 1014/1018/101c */ u8 header;
-+		/* 1015/1019/101d */ u8 quad;
-+		/* 1016/101a/101e */ u8 dual;
-+		/* 1017/101b/101f */ u8 single;
-+	} opcode[3];
-+	/* 1020 */ u32 error_control;
-+	/* 1024 */ u32 error_status; // write to clear
-+	/* 1028 */ u32 error_flags; // write to clear
-+	/* 102c */ u32 _unknown_102c[5];
-+	struct {
-+		/* 1040 */ u8 control;
-+		/* 1041 */ u8 code;
-+		/* 1042 */ u16 size;
-+		/* 1044 */ u32 status; // write to clear
-+		/* 1048 */ u32 offset;
-+		/* 104c */ u32 data[16];
-+		/* 108c */ u32 _unknown_108c;
-+	} spi_cmd;
-+	struct {
-+		/* 1090 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq()
-+		/* 1098 */ u8 control;
-+		/* 1099 */ u8 _unknown_1099;
-+		/* 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;
-+	/* 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 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;
-+		/* 1109/1209 */ u8 num_prds;
-+		/* 110a/120a */ u16 _unknown_110a;
-+		/* 110c/120c */ u8 control;
-+		/* 110d/120d */ u8 head;
-+		/* 110e/120e */ u8 tail;
-+		/* 110f/120f */ u8 control2;
-+		/* 1110/1210 */ u32 status; // write to clear
-+		/* 1114/1214 */ u32 _unknown_1114;
-+		/* 1118/1218 */ u64 _unknown_1118_guc_addr;
-+		/* 1120/1220 */ u32 _unknown_1120_guc;
-+		/* 1124/1224 */ u32 _unknown_1124_guc;
-+		/* 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[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);
-+
-+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);
-+
-+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
-new file mode 100644
-index 000000000000..aec320d4e945
---- /dev/null
-+++ b/drivers/hid/ithc/ithc.h
-@@ -0,0 +1,89 @@
-+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-+
-+#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/input.h>
-+#include <linux/io-64-nonatomic-lo-hi.h>
-+#include <linux/iopoll.h>
-+#include <linux/kthread.h>
-+#include <linux/miscdevice.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/poll.h>
-+#include <linux/timer.h>
-+#include <linux/vmalloc.h>
-+
-+#define DEVNAME "ithc"
-+#define DEVFULLNAME "Intel Touch Host Controller"
-+
-+#undef pr_fmt
-+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+
-+#define CHECK(fn, ...) ({ int r = fn(__VA_ARGS__); if (r < 0) pci_err(ithc->pci, "%s: %s failed with %i\n", __func__, #fn, r); r; })
-+#define CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0)
-+
-+#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_S_PORT1  0x7f59
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_S_PORT2  0x7f5b
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT1 0x7e49
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_MP_PORT2 0x7e4b
-+
-+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];
-+	struct pci_dev *pci;
-+	int irq;
-+	struct task_struct *poll_thread;
-+	struct timer_list idle_timer;
-+
-+	struct ithc_registers __iomem *regs;
-+	struct ithc_registers *prev_regs; // for debugging
-+	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);
-+
--- 
-2.48.1
-

+ 2 - 2
patches/6.13/0009-surface-sam-over-hid.patch → patches/6.13/0008-surface-sam-over-hid.patch

@@ -1,4 +1,4 @@
-From 543a3df85dbf28bde744266be1e5b1c747ef14dc Mon Sep 17 00:00:00 2001
+From 28db0098e37b9ac1e261afd935c0e2c5e0ae3675 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 25 Jul 2020 17:19:53 +0200
 Subject: [PATCH] i2c: acpi: Implement RawBytes read access
@@ -109,7 +109,7 @@ index d2499f302b50..77ce5ec3dd9e 100644
 -- 
 2.48.1
 
-From 591422fea78776d55694288325c4c3715b3c0f53 Mon Sep 17 00:00:00 2001
+From d7f160e91330f15f3ce5806dd2eeda08b67683e6 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 13 Feb 2021 16:41:18 +0100
 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch

+ 2 - 2
patches/6.13/0010-surface-button.patch → patches/6.13/0009-surface-button.patch

@@ -1,4 +1,4 @@
-From faeac8d73d89cb1afc128ec9f3d8f2918073edb9 Mon Sep 17 00:00:00 2001
+From cee06c726d818a4194f543f2fc99f69ed0a4a1ae Mon Sep 17 00:00:00 2001
 From: Sachi King <nakato@nakato.io>
 Date: Tue, 5 Oct 2021 00:05:09 +1100
 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices
@@ -75,7 +75,7 @@ index b8cad415c62c..43b5d56383e3 100644
 -- 
 2.48.1
 
-From 56058944284bd3dcf88182c4ae416e56121d6081 Mon Sep 17 00:00:00 2001
+From 2b8ce3b47ac424db0c4ac408c8122ccc494aa6ae Mon Sep 17 00:00:00 2001
 From: Sachi King <nakato@nakato.io>
 Date: Tue, 5 Oct 2021 00:22:57 +1100
 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd

+ 3 - 3
patches/6.13/0011-surface-typecover.patch → patches/6.13/0010-surface-typecover.patch

@@ -1,4 +1,4 @@
-From 8ee5a38b312f141f0b859fa9198f04c06c946625 Mon Sep 17 00:00:00 2001
+From db94df7d6a30c9c4125013bd195ec41d4b04a379 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sat, 18 Feb 2023 01:02:49 +0100
 Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3
@@ -39,7 +39,7 @@ index 027479179f09..ee5a6bf5452d 100644
 -- 
 2.48.1
 
-From 9faca7b71f2573df9daa0d8452f5cde816a23487 Mon Sep 17 00:00:00 2001
+From d9c734fac1446ce245a98a5f592060cc20edb158 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
 Date: Thu, 5 Nov 2020 13:09:45 +0100
 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when
@@ -274,7 +274,7 @@ index e50887a6d22c..4ce18f21a141 100644
 -- 
 2.48.1
 
-From 05ac329ac19fb1bfce5f96d57552314c2269cf73 Mon Sep 17 00:00:00 2001
+From 3e36c4a010af0175b6537a3e9b5f413e95105583 Mon Sep 17 00:00:00 2001
 From: PJungkamp <p.jungkamp@gmail.com>
 Date: Fri, 25 Feb 2022 12:04:25 +0100
 Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet

+ 1 - 1
patches/6.13/0012-surface-shutdown.patch → patches/6.13/0011-surface-shutdown.patch

@@ -1,4 +1,4 @@
-From 9b0a957384c3dac5242656fca031988a9de2776f Mon Sep 17 00:00:00 2001
+From 4f1f9492b46f9eee2ce9f844e03722acefaf5089 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sun, 19 Feb 2023 22:12:24 +0100
 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod

+ 1 - 1
patches/6.13/0013-surface-gpe.patch → patches/6.13/0012-surface-gpe.patch

@@ -1,4 +1,4 @@
-From 6b2cd94b63214bf1222a6c76c9b9fac2e7ea657f Mon Sep 17 00:00:00 2001
+From 424492cfdcccf128c28222d3bb3ba3f2ee05e3bd Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Sun, 12 Mar 2023 01:41:57 +0100
 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9

+ 10 - 10
patches/6.13/0014-cameras.patch → patches/6.13/0013-cameras.patch

@@ -1,4 +1,4 @@
-From fa2f30e8a9ffafc4b5d252710ec31ce0cc7aa305 Mon Sep 17 00:00:00 2001
+From eff5ad8dccd6f5a16bccaf8dff294af5d429e8ad Mon Sep 17 00:00:00 2001
 From: Hans de Goede <hdegoede@redhat.com>
 Date: Sun, 10 Oct 2021 20:56:57 +0200
 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an
@@ -74,7 +74,7 @@ index 74dcccdc6482..9b104f979abe 100644
 -- 
 2.48.1
 
-From 397c3bdd724c25652f126906b76b8bea75cdbdb4 Mon Sep 17 00:00:00 2001
+From fac80ec3139641ff4c494e7cd09d1648c7d8b2be Mon Sep 17 00:00:00 2001
 From: zouxiaoh <xiaohong.zou@intel.com>
 Date: Fri, 25 Jun 2021 08:52:59 +0800
 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs
@@ -184,7 +184,7 @@ index 1839a831a89f..ebd7aa6b9038 100644
 -- 
 2.48.1
 
-From abb050ef4eaa32a3215f9d9654bb6ecb5c67936c Mon Sep 17 00:00:00 2001
+From f451c52ee26ece5d7019766e438a981ef6fe112c Mon Sep 17 00:00:00 2001
 From: Daniel Scally <djrscally@gmail.com>
 Date: Sun, 10 Oct 2021 20:57:02 +0200
 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain
@@ -221,7 +221,7 @@ index 81ac4c691963..f453c9043042 100644
 -- 
 2.48.1
 
-From b7c5caad1bf9174874378fa342c6a65c5da34bb9 Mon Sep 17 00:00:00 2001
+From 04c30b68d29d35c3f1648919d191249b17f0b487 Mon Sep 17 00:00:00 2001
 From: Daniel Scally <dan.scally@ideasonboard.com>
 Date: Thu, 2 Mar 2023 12:59:39 +0000
 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E
@@ -277,7 +277,7 @@ index 09fff213b091..ce641eb45de6 100644
 -- 
 2.48.1
 
-From 7081b62ca502400be7d47b894a03106ee06c24be Mon Sep 17 00:00:00 2001
+From 45854373b2c865431add3e249e42090cb2412057 Mon Sep 17 00:00:00 2001
 From: Daniel Scally <dan.scally@ideasonboard.com>
 Date: Tue, 21 Mar 2023 13:45:26 +0000
 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251
@@ -316,7 +316,7 @@ index 30f61e04ecaf..9c1292ca8552 100644
 -- 
 2.48.1
 
-From 69725089a7927bbd3795f0251127fc79301bbb4f Mon Sep 17 00:00:00 2001
+From 7ae7dc83e5f08fafe78b6737b3d1ac6aa1c932a1 Mon Sep 17 00:00:00 2001
 From: Daniel Scally <dan.scally@ideasonboard.com>
 Date: Wed, 22 Mar 2023 11:01:42 +0000
 Subject: [PATCH] media: v4l2-core: Acquire privacy led in
@@ -367,7 +367,7 @@ index f19c8adf2c61..923ed1b5ab8b 100644
 -- 
 2.48.1
 
-From 0d33f9b4eb4a382c4d5351dced6937d2b713dd10 Mon Sep 17 00:00:00 2001
+From d20654efdf6f940456501405e90e3ed096a64258 Mon Sep 17 00:00:00 2001
 From: Kate Hsuan <hpa@redhat.com>
 Date: Tue, 21 Mar 2023 23:37:16 +0800
 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED
@@ -408,7 +408,7 @@ index f453c9043042..b8ad6b413e8b 100644
 -- 
 2.48.1
 
-From d3cf5f12bc5cda4211bbe6d7f05b2d23dce5871f Mon Sep 17 00:00:00 2001
+From b46660642fed87df97974c1eb864bff34cb5f67c Mon Sep 17 00:00:00 2001
 From: Kate Hsuan <hpa@redhat.com>
 Date: Tue, 21 Mar 2023 23:37:17 +0800
 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB
@@ -449,7 +449,7 @@ index 7807fa329db0..2d2abb25b944 100644
 -- 
 2.48.1
 
-From 0a70375485bb0c1ee51c3ec0ff20ddd3dfcdce38 Mon Sep 17 00:00:00 2001
+From 6771f76a6415179f12d68c24f599405f2ac939f1 Mon Sep 17 00:00:00 2001
 From: Kate Hsuan <hpa@redhat.com>
 Date: Tue, 21 Mar 2023 23:37:18 +0800
 Subject: [PATCH] leds: tps68470: Add LED control for tps68470
@@ -700,7 +700,7 @@ index 000000000000..35aeb5db89c8
 -- 
 2.48.1
 
-From 71dea090c37acc5f7a0dfbcc8208cab62d1dcab8 Mon Sep 17 00:00:00 2001
+From b00c21087ed9b70395b20328c11f2b43f4e07a99 Mon Sep 17 00:00:00 2001
 From: mojyack <mojyack@gmail.com>
 Date: Tue, 26 Mar 2024 05:55:44 +0900
 Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2

+ 2 - 2
patches/6.13/0015-amd-gpio.patch → patches/6.13/0014-amd-gpio.patch

@@ -1,4 +1,4 @@
-From 977d6a4eccbe4a54e06a510a7b553d9340193426 Mon Sep 17 00:00:00 2001
+From 04e4e3bd36af14f0d6d9eabbfd9b6090247e4eba Mon Sep 17 00:00:00 2001
 From: Sachi King <nakato@nakato.io>
 Date: Sat, 29 May 2021 17:47:38 +1000
 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7
@@ -65,7 +65,7 @@ index 18485170d51b..66d1b9e8aa9d 100644
 -- 
 2.48.1
 
-From 0a3a25ae02896d38edd23b947a72b9fb587b159f Mon Sep 17 00:00:00 2001
+From 438f8d54a08f27470165575040d3ee51cd943e52 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Thu, 3 Jun 2021 14:04:26 +0200
 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override

+ 1 - 1
patches/6.13/0016-rtc.patch → patches/6.13/0015-rtc.patch

@@ -1,4 +1,4 @@
-From 4d3b956038eac47f59133a636a71b73b21fd1bb0 Mon Sep 17 00:00:00 2001
+From 8b87bc2d8d00488493dc389fe768d6f9ad034fff Mon Sep 17 00:00:00 2001
 From: "Bart Groeneveld | GPX Solutions B.V" <bart@gpxbv.nl>
 Date: Mon, 5 Dec 2022 16:08:46 +0100
 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms