Sophie

Sophie

distrib > Mageia > 9 > x86_64 > by-pkgid > 733549e898e68ac22275f709b9310735 > files > 44

kernel-6.5.13-6.mga9.src.rpm

From 89dd556e38d1dc55bfda75e50d6c9154bac9f294 Mon Sep 17 00:00:00 2001
From: quo <tuple@list.ru>
Date: Mon, 23 Oct 2023 10:15:29 +0200
Subject: [PATCH 41/41] Update ITHC from module repo

Changes:
 - Added some comments and fixed a few checkpatch warnings
 - Improved CPU latency QoS handling
 - Retry reading the report descriptor on error / timeout

Based on https://github.com/quo/ithc-linux/commit/0b8b45d9775e756d6bd3a699bfaf9f5bd7b9b10b

Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
Patchset: ithc
---
 drivers/hid/ithc/ithc-debug.c |  94 +++++---
 drivers/hid/ithc/ithc-dma.c   | 231 +++++++++++++-----
 drivers/hid/ithc/ithc-dma.h   |   4 +-
 drivers/hid/ithc/ithc-main.c  | 430 ++++++++++++++++++++++++----------
 drivers/hid/ithc/ithc-regs.c  |  68 ++++--
 drivers/hid/ithc/ithc-regs.h  |  19 +-
 drivers/hid/ithc/ithc.h       |  13 +-
 7 files changed, 623 insertions(+), 236 deletions(-)

diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c
index 57bf125c45bd..1f1f1e33f2e5 100644
--- a/drivers/hid/ithc/ithc-debug.c
+++ b/drivers/hid/ithc/ithc-debug.c
@@ -1,10 +1,14 @@
+// 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++) {
+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);
@@ -13,55 +17,79 @@ void ithc_log_regs(struct ithc *ithc) {
 	}
 }
 
-static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, size_t len, loff_t *offset) {
+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;
+	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;
+	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;
+		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;
+		if (e == s)
+			return -EINVAL;
 		s = e;
 	}
 	ithc_log_regs(ithc);
-	switch(cmd[0]) {
+
+	// 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]);
+		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));
+		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;
+		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]);
+			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 < 2 || a[1] > (n - 2) * 4) return -EINVAL;
+		if (n < 2 || a[1] > (n - 2) * 4)
+			return -EINVAL;
 		pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]);
-		if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) pci_err(ithc->pci, "dma tx failed\n");
+		if (ithc_dma_tx(ithc, a[0], a[1], a + 2))
+			pci_err(ithc->pci, "dma tx failed\n");
 		break;
 	default:
 		return -EINVAL;
@@ -75,21 +103,27 @@ static const struct file_operations ithc_debugfops_cmd = {
 	.write = ithc_debugfs_cmd_write,
 };
 
-static void ithc_debugfs_devres_release(struct device *dev, void *res) {
+static void ithc_debugfs_devres_release(struct device *dev, void *res)
+{
 	struct dentry **dbgm = res;
-	if (*dbgm) debugfs_remove_recursive(*dbgm);
+	if (*dbgm)
+		debugfs_remove_recursive(*dbgm);
 }
 
-int ithc_debug_init(struct ithc *ithc) {
-	struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof *dbgm, GFP_KERNEL);
-	if (!dbgm) return -ENOMEM;
+int ithc_debug_init(struct ithc *ithc)
+{
+	struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL);
+	if (!dbgm)
+		return -ENOMEM;
 	devres_add(&ithc->pci->dev, dbgm);
 	struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL);
-	if (IS_ERR(dbg)) return PTR_ERR(dbg);
+	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);
+	if (IS_ERR(cmd))
+		return PTR_ERR(cmd);
 
 	return 0;
 }
diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c
index 7e89b3496918..ffb8689b8a78 100644
--- a/drivers/hid/ithc/ithc-dma.c
+++ b/drivers/hid/ithc/ithc-dma.c
@@ -1,59 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
 #include "ithc.h"
 
-static int ithc_dma_prd_alloc(struct ithc *ithc, struct ithc_dma_prd_buffer *p, unsigned num_buffers, unsigned num_pages, enum dma_data_direction dir) {
+// 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;
+	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) {
+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);
+		if (p)
+			__free_page(p);
 	}
 	sg_free_table(sgt);
 }
-static void ithc_dma_data_devres_release(struct device *dev, void *res) {
+static void ithc_dma_data_devres_release(struct device *dev, void *res)
+{
 	struct ithc_sg_table *sgt = res;
-	if (sgt->addr) vunmap(sgt->addr);
+	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 contiguous (we can use one PRD per page) or coherent (they are unidirectional).
-	// Instead we use an sg_table of individually allocated pages (5.13 has dma_alloc_noncontiguous for this, but we'd like to support 5.10 for now).
+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;
+	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;
+	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) {
-			struct page *p = pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); // don't need __GFP_DMA for PCI DMA
-			if (!p) { ok = false; break; }
+			// 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;
+			if (!b->addr)
+				return -ENOMEM;
 			return 0;
 		}
 		ithc_dma_sgtable_free(&sgt->sgt);
@@ -62,17 +94,29 @@ static int ithc_dma_data_alloc(struct ithc* ithc, struct ithc_dma_prd_buffer *pr
 	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 idx) {
+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; }
+	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) {
-		if (b->data_size > PAGE_SIZE) return -EINVAL;
+		// 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) {
@@ -87,21 +131,34 @@ static int ithc_dma_data_buffer_put(struct ithc *ithc, struct ithc_dma_prd_buffe
 	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 idx) {
+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;
-	if (b->active_idx != idx) { pci_err(ithc->pci, "wrong buffer index\n"); return -EINVAL; }
+	// 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 size = prd->size;
+			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; }
+			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);
@@ -110,93 +167,139 @@ static int ithc_dma_data_buffer_get(struct ithc *ithc, struct ithc_dma_prd_buffe
 	return 0;
 }
 
-int ithc_dma_rx_init(struct ithc *ithc, u8 channel, const char *devname) {
+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.
 	u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes);
-	unsigned num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
-	pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", NUM_RX_BUF, buf_size, num_pages);
+	unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
+	pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n",
+		NUM_RX_BUF, buf_size, num_pages);
 	CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE);
-	for (unsigned i = 0; i < NUM_RX_BUF; i++)
+	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; }
-	for (unsigned i = 0; i < NUM_RX_BUF; i++)
+	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[1].status, DMA_RX_STATUS_ENABLED, DMA_RX_STATUS_ENABLED);
+
+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) {
+int ithc_dma_tx_init(struct ithc *ithc)
+{
 	struct ithc_dma_tx *tx = &ithc->dma_tx;
 	mutex_init(&tx->mutex);
+
+	// Allocate buffers.
 	tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes);
-	unsigned num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE;
-	pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", tx->max_size, num_pages);
+	unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE;
+	pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n",
+		tx->max_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_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, u8 channel, u8 buf) {
+static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data,
+	u8 channel, u8 buf)
+{
 	if (buf >= NUM_RX_BUF) {
 		pci_err(ithc->pci, "invalid dma ringbuffer index\n");
 		return -EINVAL;
 	}
-	ithc_set_active(ithc);
 	u32 len = data->data_size;
 	struct ithc_dma_rx_header *hdr = data->addr;
 	u8 *hiddata = (void *)(hdr + 1);
-	if (len >= sizeof *hdr && hdr->code == DMA_RX_CODE_RESET) {
+	if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) {
+		// The THC sends a reset request when we need to reinitialize the device.
+		// This usually only happens if we send an invalid command or put the device
+		// in a bad state.
 		CHECK(ithc_reset, ithc);
-	} else if (len < sizeof *hdr || len != sizeof *hdr + hdr->data_size) {
+	} else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) {
 		if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
-			// When the CPU enters a low power state during DMA, we can get truncated messages.
-			// Typically this will be a single touch HID report that is only 1 byte, or a multitouch report that is 257 bytes.
+			// When the CPU enters a low power state during DMA, we can get truncated
+			// messages. For Surface devices, this will typically be a single touch
+			// report that is only 1 byte, or a multitouch report that is 257 bytes.
 			// See also ithc_set_active().
 		} else {
-			pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", channel, buf, len, hdr->code, hdr->data_size);
-			print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, hdr, min(len, 0x400u), 0);
+			pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n",
+				channel, buf, len, hdr->code, hdr->data_size);
+			print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
+				hdr, min(len, 0x400u), 0);
 		}
 	} else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) {
+		// Response to a 'get report descriptor' request.
+		// The actual descriptor is preceded by 8 nul bytes.
 		CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8);
 		WRITE_ONCE(ithc->hid_parse_done, true);
 		wake_up(&ithc->wait_hid_parse);
 	} else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
+		// Standard HID input report containing touch data.
 		CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1);
 	} else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) {
+		// Response to a 'get feature' request.
 		bool done = false;
 		mutex_lock(&ithc->hid_get_feature_mutex);
 		if (ithc->hid_get_feature_buf) {
-			if (hdr->data_size < ithc->hid_get_feature_size) ithc->hid_get_feature_size = hdr->data_size;
+			if (hdr->data_size < ithc->hid_get_feature_size)
+				ithc->hid_get_feature_size = hdr->data_size;
 			memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size);
 			ithc->hid_get_feature_buf = NULL;
 			done = true;
 		}
 		mutex_unlock(&ithc->hid_get_feature_mutex);
-		if (done) wake_up(&ithc->wait_hid_get_feature);
-		else CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, hiddata, hdr->data_size, 1);
+		if (done) {
+			wake_up(&ithc->wait_hid_get_feature);
+		} else {
+			// Received data without a matching request, or the request already
+			// timed out. (XXX What's the correct thing to do here?)
+			CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT,
+				hiddata, hdr->data_size, 1);
+		}
 	} else {
-		pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", channel, buf, len, hdr->code);
-		print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, hdr, min(len, 0x400u), 0);
+		pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n",
+			channel, buf, len, hdr->code);
+		print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
+			hdr, min(len, 0x400u), 0);
 	}
 	return 0;
 }
 
-static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) {
+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 n = rx->num_received;
+	unsigned int n = rx->num_received;
 	u8 head_wrap = readb(&ithc->regs->dma_rx[channel].head);
 	while (1) {
 		u8 tail = n % NUM_RX_BUF;
@@ -204,7 +307,8 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) {
 		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;
+		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];
@@ -218,7 +322,8 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) {
 		CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail);
 	}
 }
-int ithc_dma_rx(struct ithc *ithc, u8 channel) {
+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);
@@ -226,14 +331,21 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel) {
 	return ret;
 }
 
-static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) {
+static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
+{
+	ithc_set_active(ithc, 100 * USEC_PER_MSEC);
+
+	// Send a single TX buffer to the THC.
 	pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize);
 	struct ithc_dma_tx_header *hdr;
+	// Data must be padded to next 4-byte boundary.
 	u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0;
-	unsigned fullsize = sizeof *hdr + datasize + padding;
-	if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) return -EINVAL;
+	unsigned int fullsize = sizeof(*hdr) + datasize + padding;
+	if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE)
+		return -EINVAL;
 	CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
 
+	// Fill the TX buffer with header and data.
 	ithc->dma_tx.buf.data_size = fullsize;
 	hdr = ithc->dma_tx.buf.addr;
 	hdr->code = cmdcode;
@@ -241,15 +353,18 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo
 	u8 *dest = (void *)(hdr + 1);
 	memcpy(dest, data, datasize);
 	dest += datasize;
-	for (u8 p = 0; p < padding; p++) *dest++ = 0;
+	for (u8 p = 0; p < padding; p++)
+		*dest++ = 0;
 	CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
 
+	// 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, u32 cmdcode, u32 datasize, void *data) {
+int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
+{
 	mutex_lock(&ithc->dma_tx.mutex);
 	int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data);
 	mutex_unlock(&ithc->dma_tx.mutex);
diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h
index d9f2c19a13f3..93652e4476bf 100644
--- a/drivers/hid/ithc/ithc-dma.h
+++ b/drivers/hid/ithc/ithc-dma.h
@@ -1,3 +1,5 @@
+/* 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
@@ -59,7 +61,7 @@ struct ithc_dma_rx {
 	struct ithc_dma_data_buffer bufs[NUM_RX_BUF];
 };
 
-int ithc_dma_rx_init(struct ithc *ithc, u8 channel, const char *devname);
+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);
diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c
index 09512b9cb4d3..87ed4aa70fda 100644
--- a/drivers/hid/ithc/ithc-main.c
+++ b/drivers/hid/ithc/ithc-main.c
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
 #include "ithc.h"
 
 MODULE_DESCRIPTION("Intel Touch Host Controller driver");
@@ -42,6 +44,9 @@ static const struct pci_device_id ithc_pci_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT1) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_MTL_PORT2) },
+	// XXX So far the THC seems to be the only Intel PCI device with PCI_CLASS_INPUT_PEN,
+	// so instead of the device list we could just do:
+	// { .vendor = PCI_VENDOR_ID_INTEL, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .class = PCI_CLASS_INPUT_PEN, .class_mask = ~0, },
 	{}
 };
 MODULE_DEVICE_TABLE(pci, ithc_pci_tbl);
@@ -52,6 +57,7 @@ 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");
@@ -60,37 +66,56 @@ static bool ithc_use_rx1 = true;
 module_param_named(rx1, ithc_use_rx1, bool, 0);
 MODULE_PARM_DESC(rx1, "Use DMA RX channel 1");
 
+// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering.
+static int ithc_dma_latency_us = 200;
+module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0);
+MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS");
+
+// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering.
+static unsigned int ithc_dma_early_us = 2000;
+module_param_named(dma_early_us, ithc_dma_early_us, uint, 0);
+MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)");
+
 static 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)");
 
 // Sysfs attributes
 
-static bool ithc_is_config_valid(struct ithc *ithc) {
+static bool ithc_is_config_valid(struct ithc *ithc)
+{
 	return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC;
 }
 
-static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
 	struct ithc *ithc = dev_get_drvdata(dev);
-	if (!ithc || !ithc_is_config_valid(ithc)) return -ENODEV;
+	if (!ithc || !ithc_is_config_valid(ithc))
+		return -ENODEV;
 	return sprintf(buf, "0x%04x", ithc->config.vendor_id);
 }
 static DEVICE_ATTR_RO(vendor);
-static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
 	struct ithc *ithc = dev_get_drvdata(dev);
-	if (!ithc || !ithc_is_config_valid(ithc)) return -ENODEV;
+	if (!ithc || !ithc_is_config_valid(ithc))
+		return -ENODEV;
 	return sprintf(buf, "0x%04x", ithc->config.product_id);
 }
 static DEVICE_ATTR_RO(product);
-static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
 	struct ithc *ithc = dev_get_drvdata(dev);
-	if (!ithc || !ithc_is_config_valid(ithc)) return -ENODEV;
+	if (!ithc || !ithc_is_config_valid(ithc))
+		return -ENODEV;
 	return sprintf(buf, "%u", ithc->config.revision);
 }
 static DEVICE_ATTR_RO(revision);
-static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) {
+static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
 	struct ithc *ithc = dev_get_drvdata(dev);
-	if (!ithc || !ithc_is_config_valid(ithc)) return -ENODEV;
+	if (!ithc || !ithc_is_config_valid(ithc))
+		return -ENODEV;
 	u32 v = ithc->config.fw_version;
 	return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff);
 }
@@ -117,45 +142,75 @@ 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) {
+static int ithc_hid_parse(struct hid_device *hdev)
+{
 	struct ithc *ithc = hdev->driver_data;
 	u64 val = 0;
 	WRITE_ONCE(ithc->hid_parse_done, false);
-	CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof val, &val);
-	if (!wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), msecs_to_jiffies(1000))) return -ETIMEDOUT;
-	return 0;
+	for (int retries = 0; ; retries++) {
+		CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val);
+		if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done),
+				msecs_to_jiffies(200)))
+			return 0;
+		if (retries > 5) {
+			pci_err(ithc->pci, "failed to read report descriptor\n");
+			return -ETIMEDOUT;
+		}
+		pci_warn(ithc->pci, "failed to read report descriptor, retrying\n");
+	}
 }
 
-static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, size_t len, unsigned char rtype, int reqtype) {
+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;
+	if (!buf || !len)
+		return -EINVAL;
 	u32 code;
-	if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) code = DMA_TX_CODE_OUTPUT_REPORT;
-	else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) code = DMA_TX_CODE_SET_FEATURE;
-	else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) code = DMA_TX_CODE_GET_FEATURE;
-	else {
-		pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", rtype, reqtype, reportnum);
+	if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) {
+		code = DMA_TX_CODE_OUTPUT_REPORT;
+	} else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) {
+		code = DMA_TX_CODE_SET_FEATURE;
+	} else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) {
+		code = DMA_TX_CODE_GET_FEATURE;
+	} else {
+		pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n",
+			rtype, reqtype, reportnum);
 		return -EINVAL;
 	}
 	buf[0] = reportnum;
+
 	if (reqtype == HID_REQ_GET_REPORT) {
+		// Prepare for response.
 		mutex_lock(&ithc->hid_get_feature_mutex);
 		ithc->hid_get_feature_buf = buf;
 		ithc->hid_get_feature_size = len;
 		mutex_unlock(&ithc->hid_get_feature_mutex);
+
+		// Transmit 'get feature' request.
 		int r = CHECK(ithc_dma_tx, ithc, code, 1, buf);
 		if (!r) {
-			r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, !ithc->hid_get_feature_buf, msecs_to_jiffies(1000));
-			if (!r) r = -ETIMEDOUT;
-			else if (r < 0) r = -EINTR;
-			else r = 0;
+			r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature,
+				!ithc->hid_get_feature_buf, msecs_to_jiffies(1000));
+			if (!r)
+				r = -ETIMEDOUT;
+			else if (r < 0)
+				r = -EINTR;
+			else
+				r = 0;
 		}
+
+		// If everything went ok, the buffer has been filled with the response data.
+		// Return the response size.
 		mutex_lock(&ithc->hid_get_feature_mutex);
 		ithc->hid_get_feature_buf = NULL;
-		if (!r) r = ithc->hid_get_feature_size;
+		if (!r)
+			r = ithc->hid_get_feature_size;
 		mutex_unlock(&ithc->hid_get_feature_mutex);
 		return r;
 	}
+
+	// 'Set feature', or 'output report'. These don't have a response.
 	CHECK_RET(ithc_dma_tx, ithc, code, len, buf);
 	return 0;
 }
@@ -169,17 +224,22 @@ static struct hid_ll_driver ithc_ll_driver = {
 	.raw_request = ithc_hid_raw_request,
 };
 
-static void ithc_hid_devres_release(struct device *dev, void *res) {
+static void ithc_hid_devres_release(struct device *dev, void *res)
+{
 	struct hid_device **hidm = res;
-	if (*hidm) hid_destroy_device(*hidm);
+	if (*hidm)
+		hid_destroy_device(*hidm);
 }
 
-static int ithc_hid_init(struct ithc *ithc) {
-	struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof *hidm, GFP_KERNEL);
-	if (!hidm) return -ENOMEM;
+static int ithc_hid_init(struct ithc *ithc)
+{
+	struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL);
+	if (!hidm)
+		return -ENOMEM;
 	devres_add(&ithc->pci->dev, hidm);
 	struct hid_device *hid = hid_allocate_device();
-	if (IS_ERR(hid)) return PTR_ERR(hid);
+	if (IS_ERR(hid))
+		return PTR_ERR(hid);
 	*hidm = hid;
 
 	strscpy(hid->name, DEVFULLNAME, sizeof(hid->name));
@@ -198,27 +258,45 @@ static int ithc_hid_init(struct ithc *ithc) {
 
 // Interrupts/polling
 
-static void ithc_activity_timer_callback(struct timer_list *t) {
-	struct ithc *ithc = container_of(t, struct ithc, activity_timer);
-	cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t)
+{
+	struct ithc *ithc = container_of(t, struct ithc, activity_start_timer);
+	ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC);
+	return HRTIMER_NORESTART;
 }
 
-void ithc_set_active(struct ithc *ithc) {
-	// When CPU usage is very low, the CPU can enter various low power states (C2-C10).
-	// This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_UNKNOWN_12 will be set when this happens.
-	// The amount of truncated messages can become very high, resulting in user-visible effects (laggy/stuttering cursor).
-	// To avoid this, we use a CPU latency QoS request to prevent the CPU from entering low power states during touch interactions.
-	cpu_latency_qos_update_request(&ithc->activity_qos, 0);
-	mod_timer(&ithc->activity_timer, jiffies + msecs_to_jiffies(1000));
-}
-
-static int ithc_set_device_enabled(struct ithc *ithc, bool enable) {
-	u32 x = ithc->config.touch_cfg = (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2
-		| (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0);
-	return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, offsetof(struct ithc_device_config, touch_cfg), sizeof x, &x);
+static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t)
+{
+	struct ithc *ithc = container_of(t, struct ithc, activity_end_timer);
+	cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+	return HRTIMER_NORESTART;
 }
 
-static void ithc_disable_interrupts(struct ithc *ithc) {
+void ithc_set_active(struct ithc *ithc, unsigned int duration_us)
+{
+	if (ithc_dma_latency_us < 0)
+		return;
+	// When CPU usage is very low, the CPU can enter various low power states (C2-C10).
+	// This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be
+	// set when this happens. The amount of truncated messages can become very high, resulting
+	// in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency
+	// QoS request to prevent the CPU from entering low power states during touch interactions.
+	cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us);
+	hrtimer_start_range_ns(&ithc->activity_end_timer,
+		ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL);
+}
+
+static int ithc_set_device_enabled(struct ithc *ithc, bool enable)
+{
+	u32 x = ithc->config.touch_cfg =
+		(ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 |
+		(enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0);
+	return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE,
+		offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x);
+}
+
+static void ithc_disable_interrupts(struct ithc *ithc)
+{
 	writel(0, &ithc->regs->error_control);
 	bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0);
 	bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
@@ -226,43 +304,85 @@ static void ithc_disable_interrupts(struct ithc *ithc) {
 	bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0);
 }
 
-static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned channel) {
-	writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, &ithc->regs->dma_rx[channel].status);
+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel)
+{
+	writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA,
+		&ithc->regs->dma_rx[channel].status);
 }
 
-static void ithc_clear_interrupts(struct ithc *ithc) {
+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);
+	writel(DMA_TX_STATUS_DONE | DMA_TX_STATUS_ERROR | DMA_TX_STATUS_UNKNOWN_2,
+		&ithc->regs->dma_tx.status);
 }
 
-static void ithc_process(struct ithc *ithc) {
+static void ithc_process(struct ithc *ithc)
+{
 	ithc_log_regs(ithc);
 
-	// read and clear error bits
+	bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
+	bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
+
+	// Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer
+	ktime_t t = ktime_get();
+	ktime_t dt = ktime_sub(t, ithc->last_rx_time);
+	if (rx0 || rx1) {
+		ithc->last_rx_time = t;
+		if (dt > ms_to_ktime(100)) {
+			ithc->cur_rx_seq_count = 0;
+			ithc->cur_rx_seq_errors = 0;
+		}
+		ithc->cur_rx_seq_count++;
+		if (!ithc_use_polling && ithc_dma_latency_us >= 0) {
+			// Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below)
+			cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
+			hrtimer_try_to_cancel(&ithc->activity_end_timer);
+		}
+	}
+
+	// Read and clear error bits
 	u32 err = readl(&ithc->regs->error_flags);
 	if (err) {
-		if (err & ~ERROR_FLAG_DMA_UNKNOWN_12) pci_err(ithc->pci, "error flags: 0x%08x\n", err);
 		writel(err, &ithc->regs->error_flags);
+		if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT)
+			pci_err(ithc->pci, "error flags: 0x%08x\n", err);
+		if (err & ERROR_FLAG_DMA_RX_TIMEOUT) {
+			// Only log an error if we see a significant number of these errors.
+			ithc->cur_rx_seq_errors++;
+			if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10)
+				pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n",
+					ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt));
+		}
 	}
 
-	// process DMA rx
+	// Process DMA rx
 	if (ithc_use_rx0) {
 		ithc_clear_dma_rx_interrupts(ithc, 0);
-		ithc_dma_rx(ithc, 0);
+		if (rx0)
+			ithc_dma_rx(ithc, 0);
 	}
 	if (ithc_use_rx1) {
 		ithc_clear_dma_rx_interrupts(ithc, 1);
-		ithc_dma_rx(ithc, 1);
+		if (rx1)
+			ithc_dma_rx(ithc, 1);
+	}
+
+	// Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT
+	if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) {
+		ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us));
+		hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS);
 	}
 
 	ithc_log_regs(ithc);
 }
 
-static irqreturn_t ithc_interrupt_thread(int irq, void *arg) {
+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),
@@ -274,14 +394,21 @@ static irqreturn_t ithc_interrupt_thread(int irq, void *arg) {
 	return IRQ_HANDLED;
 }
 
-static int ithc_poll_thread(void *arg) {
+static int ithc_poll_thread(void *arg)
+{
 	struct ithc *ithc = arg;
-	unsigned sleep = 100;
+	unsigned int sleep = 100;
 	while (!kthread_should_stop()) {
 		u32 n = ithc->dma_rx[1].num_received;
 		ithc_process(ithc);
-		if (n != ithc->dma_rx[1].num_received) sleep = 20;
-		else sleep = min(200u, sleep + (sleep >> 4) + 1);
+		// Decrease polling interval to 20ms if we received data, otherwise slowly
+		// increase it up to 200ms.
+		if (n != ithc->dma_rx[1].num_received) {
+			ithc_set_active(ithc, 100 * USEC_PER_MSEC);
+			sleep = 20;
+		} else {
+			sleep = min(200u, sleep + (sleep >> 4) + 1);
+		}
 		msleep_interruptible(sleep);
 	}
 	return 0;
@@ -289,7 +416,8 @@ static int ithc_poll_thread(void *arg) {
 
 // Device initialization and shutdown
 
-static void ithc_disable(struct ithc *ithc) {
+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);
@@ -301,81 +429,112 @@ static void ithc_disable(struct ithc *ithc) {
 	ithc_clear_interrupts(ithc);
 }
 
-static int ithc_init_device(struct ithc *ithc) {
+static int ithc_init_device(struct ithc *ithc)
+{
 	ithc_log_regs(ithc);
 	bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0;
 	ithc_disable(ithc);
 	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY);
+
+	// Since we don't yet know which SPI config the device wants, use default speed and mode
+	// initially for reading config data.
 	ithc_set_spi_config(ithc, 10, 0);
-	bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); // seems to help with reading config
 
-	if (was_enabled) if (msleep_interruptible(100)) return -EINTR;
+	// Setting the following bit seems to make reading the config more reliable.
+	bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000);
+
+	// If the device was previously enabled, wait a bit to make sure it's fully shut down.
+	if (was_enabled)
+		if (msleep_interruptible(100))
+			return -EINTR;
+
+	// Take the touch device out of reset.
 	bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
 	CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0);
 	for (int retries = 0; ; retries++) {
 		ithc_log_regs(ithc);
 		bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET);
-		if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) break;
+		if (!waitl(ithc, &ithc->regs->state, 0xf, 2))
+			break;
 		if (retries > 5) {
-			pci_err(ithc->pci, "too many retries, failed to reset device\n");
+			pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state));
 			return -ETIMEDOUT;
 		}
-		pci_err(ithc->pci, "invalid state, retrying reset\n");
+		pci_warn(ithc->pci, "invalid state, retrying reset\n");
 		bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
-		if (msleep_interruptible(1000)) return -EINTR;
+		if (msleep_interruptible(1000))
+			return -EINTR;
 	}
 	ithc_log_regs(ithc);
 
+	// Waiting for the following status bit makes reading config much more reliable,
+	// however the official driver does not seem to do this...
 	CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4);
 
-	// read config
+	// Read configuration data.
 	for (int retries = 0; ; retries++) {
 		ithc_log_regs(ithc);
-		memset(&ithc->config, 0, sizeof ithc->config);
-		CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof ithc->config, &ithc->config);
+		memset(&ithc->config, 0, sizeof(ithc->config));
+		CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config);
 		u32 *p = (void *)&ithc->config;
 		pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
 			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
-		if (ithc_is_config_valid(ithc)) break;
+		if (ithc_is_config_valid(ithc))
+			break;
 		if (retries > 10) {
-			pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", ithc->config.device_id);
+			pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n",
+				ithc->config.device_id);
 			return -EIO;
 		}
-		pci_err(ithc->pci, "failed to read config, retrying\n");
-		if (msleep_interruptible(100)) return -EINTR;
+		pci_warn(ithc->pci, "failed to read config, retrying\n");
+		if (msleep_interruptible(100))
+			return -EINTR;
 	}
 	ithc_log_regs(ithc);
 
-	CHECK_RET(ithc_set_spi_config, ithc, DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), DEVCFG_SPI_MODE(ithc->config.spi_config));
+	// Apply SPI config and enable touch device.
+	CHECK_RET(ithc_set_spi_config, ithc,
+		DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config),
+		DEVCFG_SPI_MODE(ithc->config.spi_config));
 	CHECK_RET(ithc_set_device_enabled, ithc, true);
 	ithc_log_regs(ithc);
 	return 0;
 }
 
-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?
+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);
+	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) {
+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->poll_thread)
+		CHECK(kthread_stop, ithc->poll_thread);
+	if (ithc->irq >= 0)
+		disable_irq(ithc->irq);
 	CHECK(ithc_set_device_enabled, ithc, false);
 	ithc_disable(ithc);
-	del_timer_sync(&ithc->activity_timer);
+	hrtimer_cancel(&ithc->activity_start_timer);
+	hrtimer_cancel(&ithc->activity_end_timer);
 	cpu_latency_qos_remove_request(&ithc->activity_qos);
-	// clear dma config
-	for(unsigned i = 0; i < 2; i++) {
+
+	// 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);
@@ -383,35 +542,43 @@ static void ithc_stop(void *res) {
 	}
 	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) {
+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) {
+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;
+	if (!devres_open_group(&pci->dev, ithc_start, GFP_KERNEL))
+		return -ENOMEM;
 
-	struct ithc *ithc = devm_kzalloc(&pci->dev, sizeof *ithc, GFP_KERNEL);
-	if (!ithc) 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));
+	snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci));
 	init_waitqueue_head(&ithc->wait_hid_parse);
 	init_waitqueue_head(&ithc->wait_hid_get_feature);
 	mutex_init(&ithc->hid_get_feature_mutex);
 	pci_set_drvdata(pci, ithc);
 	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci);
-	if (ithc_log_regs_enabled) ithc->prev_regs = devm_kzalloc(&pci->dev, sizeof *ithc->prev_regs, GFP_KERNEL);
+	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");
@@ -419,29 +586,39 @@ static int ithc_start(struct pci_dev *pci) {
 	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;
+		if (ithc->irq < 0)
+			return ithc->irq;
 	}
 
+	// Initialize THC and touch device.
 	CHECK_RET(ithc_init_device, ithc);
 	CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups);
-	if (ithc_use_rx0) CHECK_RET(ithc_dma_rx_init, ithc, 0, ithc_use_rx1 ? DEVNAME "0" : DEVNAME);
-	if (ithc_use_rx1) CHECK_RET(ithc_dma_rx_init, ithc, 1, ithc_use_rx0 ? DEVNAME "1" : DEVNAME);
+	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);
 
-	CHECK_RET(ithc_hid_init, ithc);
-
 	cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-	timer_setup(&ithc->activity_timer, ithc_activity_timer_callback, 0);
+	hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	ithc->activity_start_timer.function = ithc_activity_start_timer_callback;
+	hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	ithc->activity_end_timer.function = ithc_activity_end_timer_callback;
 
-	// add ithc_stop callback AFTER setting up DMA buffers, so that polling/irqs/DMA are disabled BEFORE the buffers are freed
+	// Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are
+	// disabled BEFORE the buffers are freed.
 	CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc);
 
+	CHECK_RET(ithc_hid_init, ithc);
+
+	// Start polling/IRQ.
 	if (ithc_use_polling) {
 		pci_info(pci, "using polling instead of irq\n");
-		// use a thread instead of simple timer because we want to be able to sleep
+		// 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);
@@ -449,13 +626,17 @@ static int ithc_start(struct pci_dev *pci) {
 			return err;
 		}
 	} else {
-		CHECK_RET(devm_request_threaded_irq, &pci->dev, ithc->irq, NULL, ithc_interrupt_thread, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, DEVNAME, ithc);
+		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);
+	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
+	// hid_add_device() can only be called after irq/polling is started and DMA is enabled,
+	// because it calls ithc_hid_parse() which reads the report descriptor via DMA.
 	CHECK_RET(hid_add_device, ithc->hid);
 
 	CHECK(ithc_debug_init, ithc);
@@ -464,43 +645,54 @@ static int ithc_start(struct pci_dev *pci) {
 	return 0;
 }
 
-static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) {
+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) {
+static void ithc_remove(struct pci_dev *pci)
+{
 	pci_dbg(pci, "device remove\n");
 	// all cleanup is handled by devres
 }
 
-static int ithc_suspend(struct device *dev) {
+// 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) {
+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) {
+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) {
+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) {
+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);
@@ -521,11 +713,13 @@ static struct pci_driver ithc_driver = {
 	//.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway
 };
 
-static int __init ithc_init(void) {
+static int __init ithc_init(void)
+{
 	return pci_register_driver(&ithc_driver);
 }
 
-static void __exit ithc_exit(void) {
+static void __exit ithc_exit(void)
+{
 	pci_unregister_driver(&ithc_driver);
 }
 
diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c
index 85d567b05761..e058721886e3 100644
--- a/drivers/hid/ithc/ithc-regs.c
+++ b/drivers/hid/ithc/ithc-regs.c
@@ -1,63 +1,95 @@
+// 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);
+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);
+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) {
-	pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", reg_num(reg), mask, val);
+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val)
+{
+	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)) {
-		pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", reg_num(reg), mask, val);
+		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;
 	}
 	pci_dbg(ithc->pci, "done waiting\n");
 	return 0;
 }
 
-int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) {
-	pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", reg_num(reg), mask, val);
+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val)
+{
+	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)) {
-		pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", reg_num(reg), mask, val);
+		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;
 	}
 	pci_dbg(ithc->pci, "done waiting\n");
 	return 0;
 }
 
-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) {
+int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode)
+{
 	pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode);
-	if (mode == 3) mode = 2;
+	if (mode == 3)
+		mode = 2;
 	bitsl(&ithc->regs->spi_config,
 		SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff),
 		SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed));
 	return 0;
 }
 
-int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) {
+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data)
+{
 	pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset);
-	if (size > sizeof ithc->regs->spi_cmd.data) return -EINVAL;
+	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]);
+	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);
-	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]);
+
+	// 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
index 1a96092ed7ee..d4007d9e2bac 100644
--- a/drivers/hid/ithc/ithc-regs.h
+++ b/drivers/hid/ithc/ithc-regs.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
 #define CONTROL_QUIESCE                     BIT(1)
 #define CONTROL_IS_QUIESCED                 BIT(2)
 #define CONTROL_NRESET                      BIT(3)
@@ -24,7 +26,7 @@
 
 #define ERROR_FLAG_DMA_UNKNOWN_9            BIT(9)
 #define ERROR_FLAG_DMA_UNKNOWN_10           BIT(10)
-#define ERROR_FLAG_DMA_UNKNOWN_12           BIT(12) // set when we receive a truncated DMA message
+#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)
@@ -67,6 +69,7 @@
 #define DMA_RX_STATUS_HAVE_DATA             BIT(5)
 #define DMA_RX_STATUS_ENABLED               BIT(8)
 
+// 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 {
@@ -147,15 +150,15 @@ static_assert(sizeof(struct ithc_registers) == 0x1300);
 #define DEVCFG_SPI_MAX_FREQ(x)         (((x) >> 1) & 0xf) // high bit = use high speed mode?
 #define DEVCFG_SPI_MODE(x)             (((x) >> 6) & 3)
 #define DEVCFG_SPI_UNKNOWN_8(x)        (((x) >> 8) & 0x3f)
-#define DEVCFG_SPI_NEEDS_HEARTBEAT     BIT(20)
-#define DEVCFG_SPI_HEARTBEAT_INTERVAL  (((x) >> 21) & 7)
+#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) >> 28) & 7)
-#define DEVCFG_SPI_USE_EXT_READ_CFG    BIT(31)
+#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 {
+struct ithc_device_config { // (Example values are from an SP7+.)
 	u32 _unknown_00;      // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET)
 	u32 _unknown_04;      // 04 = 0x00000000
 	u32 dma_buf_sizes;    // 08 = 0x000a00ff
@@ -166,9 +169,9 @@ struct ithc_device_config {
 	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
+	u32 fw_version;       // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices)
 	u32 _unknown_28;      // 28 = 0x00000000
-	u32 fw_mode;          // 2c = 0x00000000
+	u32 fw_mode;          // 2c = 0x00000000 (for fw update?)
 	u32 _unknown_30;      // 30 = 0x00000000
 	u32 _unknown_34;      // 34 = 0x0404035e (u8,u8,u8,u8 = version?)
 	u32 _unknown_38;      // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET)
diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h
index 6a9b0d480bc1..028e55a4ec53 100644
--- a/drivers/hid/ithc/ithc.h
+++ b/drivers/hid/ithc/ithc.h
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
 #include <linux/module.h>
 #include <linux/input.h>
 #include <linux/hid.h>
@@ -21,7 +23,7 @@
 #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 CHECK_RET(...) do { int r = CHECK(__VA_ARGS__); if (r < 0) return r; } while (0)
 
 #define NUM_RX_BUF 16
 
@@ -35,8 +37,13 @@ struct ithc {
 	struct pci_dev *pci;
 	int irq;
 	struct task_struct *poll_thread;
+
 	struct pm_qos_request activity_qos;
-	struct timer_list activity_timer;
+	struct hrtimer activity_start_timer;
+	struct hrtimer activity_end_timer;
+	ktime_t last_rx_time;
+	unsigned int cur_rx_seq_count;
+	unsigned int cur_rx_seq_errors;
 
 	struct hid_device *hid;
 	bool hid_parse_done;
@@ -54,7 +61,7 @@ struct ithc {
 };
 
 int ithc_reset(struct ithc *ithc);
-void ithc_set_active(struct ithc *ithc);
+void ithc_set_active(struct ithc *ithc, unsigned int duration_us);
 int ithc_debug_init(struct ithc *ithc);
 void ithc_log_regs(struct ithc *ithc);
 
-- 
2.41.0