aboutsummaryrefslogtreecommitdiff
path: root/SOURCES/linux-surface.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/linux-surface.patch')
-rw-r--r--SOURCES/linux-surface.patch4876
1 files changed, 1677 insertions, 3199 deletions
diff --git a/SOURCES/linux-surface.patch b/SOURCES/linux-surface.patch
index 925163b..dd4d3b6 100644
--- a/SOURCES/linux-surface.patch
+++ b/SOURCES/linux-surface.patch
@@ -1,4 +1,4 @@
-From 24686c656a230f642f8ed6c09c184660c08cf46c Mon Sep 17 00:00:00 2001
+From fa4500c4ae1546dba5d5e4fbada8e6d0406adab0 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 9 Jun 2024 19:48:58 +0200
Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag
@@ -17,7 +17,7 @@ Patchset: secureboot
1 file changed, 4 insertions(+)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
-index b5c79f43359bc..a1bbedd989e42 100644
+index b5c79f43359b..a1bbedd989e4 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -111,7 +111,11 @@ extra_header_fields:
@@ -33,9 +33,9 @@ index b5c79f43359bc..a1bbedd989e42 100644
.long 0 # SizeOfStackReserve
.long 0 # SizeOfStackCommit
--
-2.45.1
+2.45.2
-From a494cdb84ee162accff966a0012992e36e4b0c0a Mon Sep 17 00:00:00 2001
+From b161e7d8c1f16ef72ed5195aa97e6357e06bdc4e Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 18 Oct 2020 16:42:44 +0900
Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI
@@ -77,7 +77,7 @@ Patchset: surface3-oemb
3 files changed, 24 insertions(+)
diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c
-index c15ed7a12784a..1ec8edb5aafaf 100644
+index c15ed7a12784..1ec8edb5aafa 100644
--- a/drivers/platform/surface/surface3-wmi.c
+++ b/drivers/platform/surface/surface3-wmi.c
@@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = {
@@ -95,10 +95,10 @@ index c15ed7a12784a..1ec8edb5aafaf 100644
{ }
};
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
-index d0d24a53df746..43e06166a5d95 100644
+index 51187b1e0ed2..bfb83ce8d8f8 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
-@@ -3777,6 +3777,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
+@@ -3790,6 +3790,15 @@ static const struct dmi_system_id dmi_platform_data[] = {
},
.driver_data = (void *)&intel_braswell_platform_data,
},
@@ -115,7 +115,7 @@ index d0d24a53df746..43e06166a5d95 100644
/*
* Match for the GPDwin which unfortunately uses somewhat
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
-index 5e2ec60e2954b..207868c699f29 100644
+index 5e2ec60e2954..207868c699f2 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -27,6 +27,14 @@ static const struct dmi_system_id cht_table[] = {
@@ -134,9 +134,9 @@ index 5e2ec60e2954b..207868c699f29 100644
};
--
-2.45.1
+2.45.2
-From 1abf1feb3b521abe9f9c9e8d68d2014e90ecb20d Mon Sep 17 00:00:00 2001
+From 2497b1ba9fa349ddf764c38c46160a785a5f3475 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Tue, 3 Nov 2020 13:28:04 +0100
Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface
@@ -170,7 +170,7 @@ Patchset: mwifiex
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
-index 5f997becdbaa2..9a9929424513a 100644
+index 5f997becdbaa..9a9929424513 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -1702,9 +1702,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
@@ -196,7 +196,7 @@ index 5f997becdbaa2..9a9929424513a 100644
mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr | tx_wrap);
}
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
-index dd6d21f1dbfd7..f46b06f8d6435 100644
+index dd6d21f1dbfd..f46b06f8d643 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
@@ -13,7 +13,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
@@ -289,7 +289,7 @@ index dd6d21f1dbfd7..f46b06f8d6435 100644
static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
-index d6ff964aec5bf..5d30ae39d65ec 100644
+index d6ff964aec5b..5d30ae39d65e 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
@@ -4,6 +4,7 @@
@@ -301,9 +301,9 @@ index d6ff964aec5bf..5d30ae39d65ec 100644
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
-2.45.1
+2.45.2
-From 0574bff98f5f5af132783f8f72e8ef22e3f36097 Mon Sep 17 00:00:00 2001
+From 52c3a74193a1e37e241dc8a8cef0a71e843a29b5 Mon Sep 17 00:00:00 2001
From: Tsuchiya Yuto <kitakar@gmail.com>
Date: Sun, 4 Oct 2020 00:11:49 +0900
Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+
@@ -325,7 +325,7 @@ Patchset: mwifiex
3 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
-index 9a9929424513a..2273e30297766 100644
+index 9a9929424513..2273e3029776 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -377,6 +377,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
@@ -350,7 +350,7 @@ index 9a9929424513a..2273e30297766 100644
}
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
-index f46b06f8d6435..99b024ecbadea 100644
+index f46b06f8d643..99b024ecbade 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c
@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = {
@@ -444,7 +444,7 @@ index f46b06f8d6435..99b024ecbadea 100644
static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev)
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
-index 5d30ae39d65ec..c14eb56eb9118 100644
+index 5d30ae39d65e..c14eb56eb911 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h
@@ -5,6 +5,7 @@
@@ -456,9 +456,9 @@ index 5d30ae39d65ec..c14eb56eb9118 100644
void mwifiex_initialize_quirks(struct pcie_service_card *card);
int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev);
--
-2.45.1
+2.45.2
-From 8a4ee131ced8068371a8fa09da17d82414e6d835 Mon Sep 17 00:00:00 2001
+From 338d5143d47a9de3d5a25f1fa203f6b6a95864ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl>
Date: Thu, 25 Mar 2021 11:33:02 +0100
Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell
@@ -494,7 +494,7 @@ Patchset: mwifiex
1 file changed, 15 insertions(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
-index fb716849b60f3..1e7b3798108f7 100644
+index 789c492df6fa..1e766b6c1f9a 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -65,6 +65,7 @@ static struct usb_driver btusb_driver;
@@ -513,7 +513,7 @@ index fb716849b60f3..1e7b3798108f7 100644
/* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
-@@ -4417,6 +4419,19 @@ static int btusb_probe(struct usb_interface *intf,
+@@ -4448,6 +4450,19 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
@@ -534,9 +534,9 @@ index fb716849b60f3..1e7b3798108f7 100644
(id->driver_info & BTUSB_MEDIATEK)) {
hdev->setup = btusb_mtk_setup;
--
-2.45.1
+2.45.2
-From fc56de38d725edc7c3856c2a2d369e1f170f202f Mon Sep 17 00:00:00 2001
+From 5030f889081c8676ae652623ad86b797b05d7221 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 27 Feb 2021 00:45:52 +0100
Subject: [PATCH] ath10k: Add module parameters to override board files
@@ -554,11 +554,11 @@ via a modprobe.d config.
Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: ath10k
---
- drivers/net/wireless/ath/ath10k/core.c | 58 ++++++++++++++++++++++++++
- 1 file changed, 58 insertions(+)
+ drivers/net/wireless/ath/ath10k/core.c | 57 ++++++++++++++++++++++++++
+ 1 file changed, 57 insertions(+)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
-index fa5e2e6518313..8921b0ebf36b7 100644
+index bdf0552cd1c3..e062cc687689 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -39,6 +39,9 @@ static bool fw_diag_log;
@@ -591,7 +591,7 @@ index fa5e2e6518313..8921b0ebf36b7 100644
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
.id = QCA988X_HW_2_0_VERSION,
-@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar)
+@@ -914,6 +923,42 @@ static int ath10k_init_configure_target(struct ath10k *ar)
return 0;
}
@@ -634,7 +634,7 @@ index fa5e2e6518313..8921b0ebf36b7 100644
static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
const char *dir,
const char *file)
-@@ -945,6 +990,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
+@@ -928,6 +973,18 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
if (dir == NULL)
dir = ".";
@@ -646,18 +646,17 @@ index fa5e2e6518313..8921b0ebf36b7 100644
+ * Unfortunately, that's not a solution that we can easily package. So
+ * we add module options to perform these overrides here.
+ */
-+
+ file = ath10k_override_board_fw_file(ar, file);
+ if (!file)
+ return ERR_PTR(-ENOENT);
+
- snprintf(filename, sizeof(filename), "%s/%s", dir, file);
- ret = firmware_request_nowarn(&fw, filename, ar->dev);
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",
+ if (ar->board_name) {
+ snprintf(filename, sizeof(filename), "%s/%s/%s",
+ dir, ar->board_name, file);
--
-2.45.1
+2.45.2
-From ee272e8a81f073b5475a3bb2c3085b55f181bc24 Mon Sep 17 00:00:00 2001
+From 318ef833ea6bf3a2ef7566bad79931b216bd7423 Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Thu, 30 Jul 2020 13:21:53 +0200
Subject: [PATCH] mei: me: Add Icelake device ID for iTouch
@@ -670,7 +669,7 @@ Patchset: ipts
2 files changed, 2 insertions(+)
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
-index c3a6657dcd4a2..82eef2f4eb0a8 100644
+index c3a6657dcd4a..82eef2f4eb0a 100644
--- a/drivers/misc/mei/hw-me-regs.h
+++ b/drivers/misc/mei/hw-me-regs.h
@@ -92,6 +92,7 @@
@@ -682,7 +681,7 @@ index c3a6657dcd4a2..82eef2f4eb0a8 100644
#define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
-index 7f59dd38c32f5..a56ad5b3f7790 100644
+index 6589635f8ba3..a1df48a434e2 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -97,6 +97,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
@@ -694,9 +693,9 @@ index 7f59dd38c32f5..a56ad5b3f7790 100644
{MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
--
-2.45.1
+2.45.2
-From 8536601cfc6d7671f4c11cab4dca57674f59b349 Mon Sep 17 00:00:00 2001
+From ddcd34d797494f38ba7be0d9e46a919fda557576 Mon Sep 17 00:00:00 2001
From: Liban Hannan <liban.p@gmail.com>
Date: Tue, 12 Apr 2022 23:31:12 +0100
Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS
@@ -720,10 +719,10 @@ Patchset: ipts
1 file changed, 29 insertions(+)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
-index e4a03588a8a0f..61bc54299a591 100644
+index f55ec1fd7942..8d95579436a9 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
-@@ -39,6 +39,11 @@
+@@ -40,6 +40,11 @@
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -735,7 +734,7 @@ index e4a03588a8a0f..61bc54299a591 100644
#define IOAPIC_RANGE_START (0xfee00000)
#define IOAPIC_RANGE_END (0xfeefffff)
#define IOVA_START_ADDR (0x1000)
-@@ -221,12 +226,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
+@@ -217,12 +222,14 @@ int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);
int intel_iommu_enabled = 0;
EXPORT_SYMBOL_GPL(intel_iommu_enabled);
@@ -750,7 +749,7 @@ index e4a03588a8a0f..61bc54299a591 100644
const struct iommu_ops intel_iommu_ops;
static const struct iommu_dirty_ops intel_dirty_ops;
-@@ -2401,6 +2408,9 @@ static int device_def_domain_type(struct device *dev)
+@@ -2195,6 +2202,9 @@ static int device_def_domain_type(struct device *dev)
if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
return IOMMU_DOMAIN_IDENTITY;
@@ -760,7 +759,7 @@ index e4a03588a8a0f..61bc54299a591 100644
}
return 0;
-@@ -2701,6 +2711,9 @@ static int __init init_dmars(void)
+@@ -2495,6 +2505,9 @@ static int __init init_dmars(void)
iommu_set_root_entry(iommu);
}
@@ -770,7 +769,7 @@ index e4a03588a8a0f..61bc54299a591 100644
check_tylersburg_isoch();
ret = si_domain_init(hw_pass_through);
-@@ -4871,6 +4884,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
+@@ -4617,6 +4630,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
disable_igfx_iommu = 1;
}
@@ -789,7 +788,7 @@ index e4a03588a8a0f..61bc54299a591 100644
/* G4x/GM45 integrated gfx dmar support is totally busted. */
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2e00, quirk_iommu_igfx);
-@@ -4906,6 +4931,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
+@@ -4652,6 +4677,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx);
@@ -801,9 +800,9 @@ index e4a03588a8a0f..61bc54299a591 100644
{
if (risky_device(dev))
--
-2.45.1
+2.45.2
-From 664128ab9984f6c774d4064548d9b247041d2520 Mon Sep 17 00:00:00 2001
+From 6ff2cce19a707fb565e9aebf9fb2b00fe845a46a Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Sun, 11 Dec 2022 12:00:59 +0100
Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus
@@ -823,16 +822,16 @@ Patchset: ipts
drivers/hid/ipts/control.c | 486 +++++++++++++++++++++++++++++++++
drivers/hid/ipts/control.h | 126 +++++++++
drivers/hid/ipts/desc.h | 80 ++++++
- drivers/hid/ipts/eds1.c | 103 +++++++
+ drivers/hid/ipts/eds1.c | 104 +++++++
drivers/hid/ipts/eds1.h | 35 +++
- drivers/hid/ipts/eds2.c | 144 ++++++++++
+ drivers/hid/ipts/eds2.c | 145 ++++++++++
drivers/hid/ipts/eds2.h | 35 +++
drivers/hid/ipts/hid.c | 225 +++++++++++++++
drivers/hid/ipts/hid.h | 24 ++
drivers/hid/ipts/main.c | 126 +++++++++
drivers/hid/ipts/mei.c | 188 +++++++++++++
drivers/hid/ipts/mei.h | 66 +++++
- drivers/hid/ipts/receiver.c | 250 +++++++++++++++++
+ drivers/hid/ipts/receiver.c | 251 +++++++++++++++++
drivers/hid/ipts/receiver.h | 16 ++
drivers/hid/ipts/resources.c | 131 +++++++++
drivers/hid/ipts/resources.h | 41 +++
@@ -841,7 +840,7 @@ Patchset: ipts
drivers/hid/ipts/spec-hid.h | 34 +++
drivers/hid/ipts/thread.c | 84 ++++++
drivers/hid/ipts/thread.h | 59 ++++
- 28 files changed, 2850 insertions(+)
+ 28 files changed, 2853 insertions(+)
create mode 100644 drivers/hid/ipts/Kconfig
create mode 100644 drivers/hid/ipts/Makefile
create mode 100644 drivers/hid/ipts/cmd.c
@@ -870,10 +869,10 @@ Patchset: ipts
create mode 100644 drivers/hid/ipts/thread.h
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
-index 4c682c6507040..a263e49b2ae29 100644
+index 08446c89eff6..ccddfba86004 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
-@@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
+@@ -1367,4 +1367,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig"
source "drivers/hid/surface-hid/Kconfig"
@@ -881,10 +880,10 @@ index 4c682c6507040..a263e49b2ae29 100644
+
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index 082a728eac600..f4bad1b8d813f 100644
+index ce71b53ea6c5..de41081b6a5a 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
-@@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
+@@ -171,3 +171,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/
@@ -892,7 +891,7 @@ index 082a728eac600..f4bad1b8d813f 100644
+obj-$(CONFIG_HID_IPTS) += ipts/
diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig
new file mode 100644
-index 0000000000000..297401bd388dd
+index 000000000000..297401bd388d
--- /dev/null
+++ b/drivers/hid/ipts/Kconfig
@@ -0,0 +1,14 @@
@@ -912,7 +911,7 @@ index 0000000000000..297401bd388dd
+ module will be called ipts.
diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile
new file mode 100644
-index 0000000000000..883896f68e6ad
+index 000000000000..883896f68e6a
--- /dev/null
+++ b/drivers/hid/ipts/Makefile
@@ -0,0 +1,16 @@
@@ -934,7 +933,7 @@ index 0000000000000..883896f68e6ad
+ipts-objs += thread.o
diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c
new file mode 100644
-index 0000000000000..63a4934bbc5fa
+index 000000000000..63a4934bbc5f
--- /dev/null
+++ b/drivers/hid/ipts/cmd.c
@@ -0,0 +1,61 @@
@@ -1001,7 +1000,7 @@ index 0000000000000..63a4934bbc5fa
+}
diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h
new file mode 100644
-index 0000000000000..2b4079075b642
+index 000000000000..2b4079075b64
--- /dev/null
+++ b/drivers/hid/ipts/cmd.h
@@ -0,0 +1,60 @@
@@ -1067,7 +1066,7 @@ index 0000000000000..2b4079075b642
+#endif /* IPTS_CMD_H */
diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h
new file mode 100644
-index 0000000000000..ba33259f1f7c5
+index 000000000000..ba33259f1f7c
--- /dev/null
+++ b/drivers/hid/ipts/context.h
@@ -0,0 +1,52 @@
@@ -1125,7 +1124,7 @@ index 0000000000000..ba33259f1f7c5
+#endif /* IPTS_CONTEXT_H */
diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c
new file mode 100644
-index 0000000000000..5360842d260ba
+index 000000000000..5360842d260b
--- /dev/null
+++ b/drivers/hid/ipts/control.c
@@ -0,0 +1,486 @@
@@ -1617,7 +1616,7 @@ index 0000000000000..5360842d260ba
+}
diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h
new file mode 100644
-index 0000000000000..26629c5144edb
+index 000000000000..26629c5144ed
--- /dev/null
+++ b/drivers/hid/ipts/control.h
@@ -0,0 +1,126 @@
@@ -1749,7 +1748,7 @@ index 0000000000000..26629c5144edb
+#endif /* IPTS_CONTROL_H */
diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h
new file mode 100644
-index 0000000000000..307438c7c80cd
+index 000000000000..307438c7c80c
--- /dev/null
+++ b/drivers/hid/ipts/desc.h
@@ -0,0 +1,80 @@
@@ -1835,10 +1834,10 @@ index 0000000000000..307438c7c80cd
+#endif /* IPTS_DESC_H */
diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c
new file mode 100644
-index 0000000000000..ecbb3a8bdaf60
+index 000000000000..7b9f54388a9f
--- /dev/null
+++ b/drivers/hid/ipts/eds1.c
-@@ -0,0 +1,103 @@
+@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Dorian Stoll
@@ -1855,6 +1854,7 @@ index 0000000000000..ecbb3a8bdaf60
+#include "context.h"
+#include "control.h"
+#include "desc.h"
++#include "eds1.h"
+#include "spec-device.h"
+
+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
@@ -1944,7 +1944,7 @@ index 0000000000000..ecbb3a8bdaf60
+}
diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h
new file mode 100644
-index 0000000000000..eeeb6575e3e89
+index 000000000000..eeeb6575e3e8
--- /dev/null
+++ b/drivers/hid/ipts/eds1.h
@@ -0,0 +1,35 @@
@@ -1985,10 +1985,10 @@ index 0000000000000..eeeb6575e3e89
+ enum hid_report_type report_type, enum hid_class_request request_type);
diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c
new file mode 100644
-index 0000000000000..198dc65d78876
+index 000000000000..639940794615
--- /dev/null
+++ b/drivers/hid/ipts/eds2.c
-@@ -0,0 +1,144 @@
+@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Dorian Stoll
@@ -2006,6 +2006,7 @@ index 0000000000000..198dc65d78876
+#include "context.h"
+#include "control.h"
+#include "desc.h"
++#include "eds2.h"
+#include "spec-data.h"
+
+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
@@ -2135,7 +2136,7 @@ index 0000000000000..198dc65d78876
+}
diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h
new file mode 100644
-index 0000000000000..064e3716907ab
+index 000000000000..064e3716907a
--- /dev/null
+++ b/drivers/hid/ipts/eds2.h
@@ -0,0 +1,35 @@
@@ -2176,7 +2177,7 @@ index 0000000000000..064e3716907ab
+ enum hid_report_type report_type, enum hid_class_request request_type);
diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c
new file mode 100644
-index 0000000000000..e34a1a4f9fa77
+index 000000000000..e34a1a4f9fa7
--- /dev/null
+++ b/drivers/hid/ipts/hid.c
@@ -0,0 +1,225 @@
@@ -2407,7 +2408,7 @@ index 0000000000000..e34a1a4f9fa77
+}
diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h
new file mode 100644
-index 0000000000000..1ebe77447903a
+index 000000000000..1ebe77447903
--- /dev/null
+++ b/drivers/hid/ipts/hid.h
@@ -0,0 +1,24 @@
@@ -2437,7 +2438,7 @@ index 0000000000000..1ebe77447903a
+#endif /* IPTS_HID_H */
diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c
new file mode 100644
-index 0000000000000..fb5b5c13ee3ea
+index 000000000000..fb5b5c13ee3e
--- /dev/null
+++ b/drivers/hid/ipts/main.c
@@ -0,0 +1,126 @@
@@ -2569,7 +2570,7 @@ index 0000000000000..fb5b5c13ee3ea
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c
new file mode 100644
-index 0000000000000..1e0395ceae4a4
+index 000000000000..1e0395ceae4a
--- /dev/null
+++ b/drivers/hid/ipts/mei.c
@@ -0,0 +1,188 @@
@@ -2763,7 +2764,7 @@ index 0000000000000..1e0395ceae4a4
+}
diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h
new file mode 100644
-index 0000000000000..973bade6b0fdd
+index 000000000000..973bade6b0fd
--- /dev/null
+++ b/drivers/hid/ipts/mei.h
@@ -0,0 +1,66 @@
@@ -2835,10 +2836,10 @@ index 0000000000000..973bade6b0fdd
+#endif /* IPTS_MEI_H */
diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c
new file mode 100644
-index 0000000000000..ef66c3c9db807
+index 000000000000..977724c728c3
--- /dev/null
+++ b/drivers/hid/ipts/receiver.c
-@@ -0,0 +1,250 @@
+@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020-2023 Dorian Stoll
@@ -2857,6 +2858,7 @@ index 0000000000000..ef66c3c9db807
+#include "context.h"
+#include "control.h"
+#include "hid.h"
++#include "receiver.h"
+#include "resources.h"
+#include "spec-device.h"
+#include "thread.h"
@@ -3091,7 +3093,7 @@ index 0000000000000..ef66c3c9db807
+}
diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h
new file mode 100644
-index 0000000000000..3de7da62d40c1
+index 000000000000..3de7da62d40c
--- /dev/null
+++ b/drivers/hid/ipts/receiver.h
@@ -0,0 +1,16 @@
@@ -3113,7 +3115,7 @@ index 0000000000000..3de7da62d40c1
+#endif /* IPTS_RECEIVER_H */
diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c
new file mode 100644
-index 0000000000000..cc14653b2a9f5
+index 000000000000..cc14653b2a9f
--- /dev/null
+++ b/drivers/hid/ipts/resources.c
@@ -0,0 +1,131 @@
@@ -3250,7 +3252,7 @@ index 0000000000000..cc14653b2a9f5
+}
diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h
new file mode 100644
-index 0000000000000..2068e13285f0e
+index 000000000000..2068e13285f0
--- /dev/null
+++ b/drivers/hid/ipts/resources.h
@@ -0,0 +1,41 @@
@@ -3297,7 +3299,7 @@ index 0000000000000..2068e13285f0e
+#endif /* IPTS_RESOURCES_H */
diff --git a/drivers/hid/ipts/spec-data.h b/drivers/hid/ipts/spec-data.h
new file mode 100644
-index 0000000000000..e8dd98895a7ee
+index 000000000000..e8dd98895a7e
--- /dev/null
+++ b/drivers/hid/ipts/spec-data.h
@@ -0,0 +1,100 @@
@@ -3403,7 +3405,7 @@ index 0000000000000..e8dd98895a7ee
+#endif /* IPTS_SPEC_DATA_H */
diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h
new file mode 100644
-index 0000000000000..41845f9d90257
+index 000000000000..41845f9d9025
--- /dev/null
+++ b/drivers/hid/ipts/spec-device.h
@@ -0,0 +1,290 @@
@@ -3699,7 +3701,7 @@ index 0000000000000..41845f9d90257
+#endif /* IPTS_SPEC_DEVICE_H */
diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h
new file mode 100644
-index 0000000000000..5a58d4a0a610f
+index 000000000000..5a58d4a0a610
--- /dev/null
+++ b/drivers/hid/ipts/spec-hid.h
@@ -0,0 +1,34 @@
@@ -3739,7 +3741,7 @@ index 0000000000000..5a58d4a0a610f
+#endif /* IPTS_SPEC_HID_H */
diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c
new file mode 100644
-index 0000000000000..355e92bea26f8
+index 000000000000..355e92bea26f
--- /dev/null
+++ b/drivers/hid/ipts/thread.c
@@ -0,0 +1,84 @@
@@ -3829,7 +3831,7 @@ index 0000000000000..355e92bea26f8
+}
diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h
new file mode 100644
-index 0000000000000..1f966b8b32c45
+index 000000000000..1f966b8b32c4
--- /dev/null
+++ b/drivers/hid/ipts/thread.h
@@ -0,0 +1,59 @@
@@ -3893,62 +3895,9 @@ index 0000000000000..1f966b8b32c45
+
+#endif /* IPTS_THREAD_H */
--
-2.45.1
-
-From ee8823ff409dc4507cc2f7c8f8c474735b005938 Mon Sep 17 00:00:00 2001
-From: Jasmin Huber <jasmin@jasisonee.ch>
-Date: Mon, 15 Apr 2024 10:22:55 +0200
-Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile
- with -Wmissing-prototypes.
+2.45.2
-Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
-Patchset: ipts
----
- drivers/hid/ipts/eds1.c | 1 +
- drivers/hid/ipts/eds2.c | 1 +
- drivers/hid/ipts/receiver.c | 1 +
- 3 files changed, 3 insertions(+)
-
-diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c
-index ecbb3a8bdaf60..7b9f54388a9f6 100644
---- a/drivers/hid/ipts/eds1.c
-+++ b/drivers/hid/ipts/eds1.c
-@@ -14,6 +14,7 @@
- #include "context.h"
- #include "control.h"
- #include "desc.h"
-+#include "eds1.h"
- #include "spec-device.h"
-
- int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
-diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c
-index 198dc65d78876..639940794615d 100644
---- a/drivers/hid/ipts/eds2.c
-+++ b/drivers/hid/ipts/eds2.c
-@@ -15,6 +15,7 @@
- #include "context.h"
- #include "control.h"
- #include "desc.h"
-+#include "eds2.h"
- #include "spec-data.h"
-
- int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size)
-diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c
-index ef66c3c9db807..977724c728c3e 100644
---- a/drivers/hid/ipts/receiver.c
-+++ b/drivers/hid/ipts/receiver.c
-@@ -16,6 +16,7 @@
- #include "context.h"
- #include "control.h"
- #include "hid.h"
-+#include "receiver.h"
- #include "resources.h"
- #include "spec-device.h"
- #include "thread.h"
---
-2.45.1
-
-From 4b17942da35790b0e703a87267545f5a9f08e1cf Mon Sep 17 00:00:00 2001
+From 52e90ab224f06fd648ca85cd43a91670a9a4e683 Mon Sep 17 00:00:00 2001
From: Dorian Stoll <dorian.stoll@tmsp.io>
Date: Sun, 11 Dec 2022 12:03:38 +0100
Subject: [PATCH] iommu: intel: Disable source id verification for ITHC
@@ -3960,10 +3909,10 @@ Patchset: ithc
1 file changed, 16 insertions(+)
diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c
-index 566297bc87ddb..a8cd8f12d5937 100644
+index e4a70886678c..961a33b87c24 100644
--- a/drivers/iommu/intel/irq_remapping.c
+++ b/drivers/iommu/intel/irq_remapping.c
-@@ -386,6 +386,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
+@@ -389,6 +389,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev)
data.busmatch_count = 0;
pci_for_each_dma_alias(dev, set_msi_sid_cb, &data);
@@ -3987,45 +3936,59 @@ index 566297bc87ddb..a8cd8f12d5937 100644
* DMA alias provides us with a PCI device and alias. The only case
* where the it will return an alias on a different bus than the
--
-2.45.1
+2.45.2
-From 14baff1c79b6499868b48e6fb4ada851db35c941 Mon Sep 17 00:00:00 2001
+From a5da515376d209ea8610fed94888f48d9b64387f 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@0b8b45d
+Based on quo/ithc-linux@34539af4726d.
-Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
+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 | 130 ++++++
- drivers/hid/ithc/ithc-dma.c | 373 +++++++++++++++++
- drivers/hid/ithc/ithc-dma.h | 69 ++++
- drivers/hid/ithc/ithc-main.c | 728 ++++++++++++++++++++++++++++++++++
- drivers/hid/ithc/ithc-regs.c | 96 +++++
- drivers/hid/ithc/ithc-regs.h | 189 +++++++++
- drivers/hid/ithc/ithc.h | 67 ++++
- 11 files changed, 1673 insertions(+)
+ 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 a263e49b2ae29..03f0f5af289a4 100644
+index ccddfba86004..8e2ea8175bfb 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
-@@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig"
+@@ -1369,4 +1369,6 @@ source "drivers/hid/surface-hid/Kconfig"
source "drivers/hid/ipts/Kconfig"
@@ -4033,29 +3996,29 @@ index a263e49b2ae29..03f0f5af289a4 100644
+
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
-index f4bad1b8d813f..d32c194400aea 100644
+index de41081b6a5a..9d156f1b3910 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
-@@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/
+@@ -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 0000000000000..aea83f2ac07b4
+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-debug.o
++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o
+
+ccflags-y := -std=gnu11 -Wno-declaration-after-statement
+
diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig
new file mode 100644
-index 0000000000000..ede7130236096
+index 000000000000..ede713023609
--- /dev/null
+++ b/drivers/hid/ithc/Kconfig
@@ -0,0 +1,12 @@
@@ -4073,10 +4036,10 @@ index 0000000000000..ede7130236096
+ 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 0000000000000..1f1f1e33f2e5a
+index 000000000000..2d8c6afe9966
--- /dev/null
+++ b/drivers/hid/ithc/ithc-debug.c
-@@ -0,0 +1,130 @@
+@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+#include "ithc.h"
@@ -4164,10 +4127,11 @@ index 0000000000000..1f1f1e33f2e5a
+ case 'd': // dma command: cmd len data...
+ // get report descriptor: d 7 8 0 0
+ // enable multitouch: d 3 2 0x0105
-+ if (n < 2 || a[1] > (n - 2) * 4)
++ if (n < 1)
+ return -EINVAL;
-+ pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]);
-+ if (ithc_dma_tx(ithc, a[0], a[1], a + 2))
++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4);
++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a };
++ if (ithc_dma_tx(ithc, &data))
+ pci_err(ithc->pci, "dma tx failed\n");
+ break;
+ default:
@@ -4177,6 +4141,23 @@ index 0000000000000..1f1f1e33f2e5a
+ 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,
@@ -4185,17 +4166,18 @@ index 0000000000000..1f1f1e33f2e5a
+static void ithc_debugfs_devres_release(struct device *dev, void *res)
+{
+ struct dentry **dbgm = res;
-+ if (*dbgm)
-+ debugfs_remove_recursive(*dbgm);
++ debugfs_remove_recursive(*dbgm);
+}
+
-+int ithc_debug_init(struct ithc *ithc)
++int ithc_debug_init_device(struct ithc *ithc)
+{
++ if (!dbg_dir)
++ return -ENOENT;
+ struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL);
+ if (!dbgm)
+ return -ENOMEM;
+ devres_add(&ithc->pci->dev, dbgm);
-+ struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL);
++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir);
+ if (IS_ERR(dbg))
+ return PTR_ERR(dbg);
+ *dbgm = dbg;
@@ -4207,12 +4189,25 @@ index 0000000000000..1f1f1e33f2e5a
+ 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 0000000000000..ffb8689b8a780
+index 000000000000..bf4eab33062b
--- /dev/null
+++ b/drivers/hid/ithc/ithc-dma.c
-@@ -0,0 +1,373 @@
+@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+#include "ithc.h"
@@ -4388,10 +4383,9 @@ index 0000000000000..ffb8689b8a780
+ mutex_init(&rx->mutex);
+
+ // Allocate buffers.
-+ u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes);
-+ unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n",
-+ NUM_RX_BUF, buf_size, num_pages);
++ NUM_RX_BUF, ithc->max_rx_size, num_pages);
+ CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE);
+ for (unsigned int i = 0; i < NUM_RX_BUF; i++)
+ CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]);
@@ -4429,10 +4423,9 @@ index 0000000000000..ffb8689b8a780
+ mutex_init(&tx->mutex);
+
+ // Allocate buffers.
-+ tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes);
-+ unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE;
++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE;
+ pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n",
-+ tx->max_size, num_pages);
++ ithc->max_tx_size, num_pages);
+ CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE);
+ CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf);
+
@@ -4445,71 +4438,6 @@ index 0000000000000..ffb8689b8a780
+ return 0;
+}
+
-+static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data,
-+ u8 channel, u8 buf)
-+{
-+ if (buf >= NUM_RX_BUF) {
-+ pci_err(ithc->pci, "invalid dma ringbuffer index\n");
-+ return -EINVAL;
-+ }
-+ u32 len = data->data_size;
-+ struct ithc_dma_rx_header *hdr = data->addr;
-+ u8 *hiddata = (void *)(hdr + 1);
-+ if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) {
-+ // The THC sends a reset request when we need to reinitialize the device.
-+ // This usually only happens if we send an invalid command or put the device
-+ // in a bad state.
-+ CHECK(ithc_reset, ithc);
-+ } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) {
-+ if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
-+ // When the CPU enters a low power state during DMA, we can get truncated
-+ // messages. For Surface devices, this will typically be a single touch
-+ // report that is only 1 byte, or a multitouch report that is 257 bytes.
-+ // See also ithc_set_active().
-+ } else {
-+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n",
-+ channel, buf, len, hdr->code, hdr->data_size);
-+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
-+ hdr, min(len, 0x400u), 0);
-+ }
-+ } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) {
-+ // Response to a 'get report descriptor' request.
-+ // The actual descriptor is preceded by 8 nul bytes.
-+ CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8);
-+ WRITE_ONCE(ithc->hid_parse_done, true);
-+ wake_up(&ithc->wait_hid_parse);
-+ } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
-+ // Standard HID input report containing touch data.
-+ CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1);
-+ } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) {
-+ // Response to a 'get feature' request.
-+ bool done = false;
-+ mutex_lock(&ithc->hid_get_feature_mutex);
-+ if (ithc->hid_get_feature_buf) {
-+ if (hdr->data_size < ithc->hid_get_feature_size)
-+ ithc->hid_get_feature_size = hdr->data_size;
-+ memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size);
-+ ithc->hid_get_feature_buf = NULL;
-+ done = true;
-+ }
-+ mutex_unlock(&ithc->hid_get_feature_mutex);
-+ if (done) {
-+ wake_up(&ithc->wait_hid_get_feature);
-+ } else {
-+ // Received data without a matching request, or the request already
-+ // timed out. (XXX What's the correct thing to do here?)
-+ CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT,
-+ hiddata, hdr->data_size, 1);
-+ }
-+ } else {
-+ pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n",
-+ channel, buf, len, hdr->code);
-+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
-+ hdr, min(len, 0x400u), 0);
-+ }
-+ return 0;
-+}
-+
+static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
+{
+ // Process all filled RX buffers from the ringbuffer.
@@ -4531,7 +4459,16 @@ index 0000000000000..ffb8689b8a780
+ rx->num_received = ++n;
+
+ // process data
-+ CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail);
++ struct ithc_data d;
++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx)
++ (ithc, b->addr, b->data_size, &d) < 0) {
++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n",
++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr);
++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
++ b->addr, min(b->data_size, 0x400u), 0);
++ } else {
++ ithc_hid_process_data(ithc, &d);
++ }
+
+ // give the buffer back to the device
+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail);
@@ -4546,31 +4483,28 @@ index 0000000000000..ffb8689b8a780
+ return ret;
+}
+
-+static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data)
+{
-+ ithc_set_active(ithc, 100 * USEC_PER_MSEC);
-+
+ // Send a single TX buffer to the THC.
-+ pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize);
-+ struct ithc_dma_tx_header *hdr;
-+ // Data must be padded to next 4-byte boundary.
-+ u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0;
-+ unsigned int fullsize = sizeof(*hdr) + datasize + padding;
-+ if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE)
-+ return -EINVAL;
++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size);
+ CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
+
+ // Fill the TX buffer with header and data.
-+ ithc->dma_tx.buf.data_size = fullsize;
-+ hdr = ithc->dma_tx.buf.addr;
-+ hdr->code = cmdcode;
-+ hdr->data_size = datasize;
-+ u8 *dest = (void *)(hdr + 1);
-+ memcpy(dest, data, datasize);
-+ dest += datasize;
-+ for (u8 p = 0; p < padding; p++)
-+ *dest++ = 0;
++ ssize_t sz;
++ if (data->type == ITHC_DATA_RAW) {
++ sz = min(data->size, ithc->max_tx_size);
++ memcpy(ithc->dma_tx.buf.addr, data->data, sz);
++ } else {
++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx)
++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size);
++ }
++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz;
+ CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
++ if (sz < 0) {
++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n",
++ data->type, data->size, (int)sz);
++ return -EINVAL;
++ }
+
+ // Let the THC process the buffer.
+ bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND);
@@ -4578,20 +4512,20 @@ index 0000000000000..ffb8689b8a780
+ writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status);
+ return 0;
+}
-+int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data)
+{
+ mutex_lock(&ithc->dma_tx.mutex);
-+ int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data);
++ int ret = ithc_dma_tx_unlocked(ithc, data);
+ mutex_unlock(&ithc->dma_tx.mutex);
+ return ret;
+}
+
diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h
new file mode 100644
-index 0000000000000..93652e4476bf8
+index 000000000000..1749a5819b3e
--- /dev/null
+++ b/drivers/hid/ithc/ithc-dma.h
-@@ -0,0 +1,69 @@
+@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
+
+#define PRD_SIZE_MASK 0xffffff
@@ -4605,27 +4539,6 @@ index 0000000000000..93652e4476bf8
+ u32 unused;
+};
+
-+#define DMA_RX_CODE_INPUT_REPORT 3
-+#define DMA_RX_CODE_FEATURE_REPORT 4
-+#define DMA_RX_CODE_REPORT_DESCRIPTOR 5
-+#define DMA_RX_CODE_RESET 7
-+
-+struct ithc_dma_rx_header {
-+ u32 code;
-+ u32 data_size;
-+ u32 _unknown[14];
-+};
-+
-+#define DMA_TX_CODE_SET_FEATURE 3
-+#define DMA_TX_CODE_GET_FEATURE 4
-+#define DMA_TX_CODE_OUTPUT_REPORT 5
-+#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7
-+
-+struct ithc_dma_tx_header {
-+ u32 code;
-+ u32 data_size;
-+};
-+
+struct ithc_dma_prd_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
@@ -4643,7 +4556,6 @@ index 0000000000000..93652e4476bf8
+
+struct ithc_dma_tx {
+ struct mutex mutex;
-+ u32 max_size;
+ struct ithc_dma_prd_buffer prds;
+ struct ithc_dma_data_buffer buf;
+};
@@ -4659,1474 +4571,11 @@ index 0000000000000..93652e4476bf8
+void ithc_dma_rx_enable(struct ithc *ithc, u8 channel);
+int ithc_dma_tx_init(struct ithc *ithc);
+int ithc_dma_rx(struct ithc *ithc, u8 channel);
-+int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata);
-+
-diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c
-new file mode 100644
-index 0000000000000..87ed4aa70fda0
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-main.c
-@@ -0,0 +1,728 @@
-+// 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");
-+
-+// Lakefield
-+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0
-+#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1
-+// Tiger Lake
-+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0
-+#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1
-+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0
-+#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1
-+// Alder Lake
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0
-+#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1
-+// Raptor Lake
-+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58
-+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59
-+// Meteor Lake
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a
-+
-+static const struct pci_device_id ithc_pci_tbl[] = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1) },
-+ { 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);
-+
-+// 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");
-+
-+// 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)
-+{
-+ return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC;
-+}
-+
-+static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
-+{
-+ struct ithc *ithc = dev_get_drvdata(dev);
-+ if (!ithc || !ithc_is_config_valid(ithc))
-+ 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)
-+{
-+ struct ithc *ithc = dev_get_drvdata(dev);
-+ 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)
-+{
-+ struct ithc *ithc = dev_get_drvdata(dev);
-+ 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)
-+{
-+ struct ithc *ithc = dev_get_drvdata(dev);
-+ if (!ithc || !ithc_is_config_valid(ithc))
-+ return -ENODEV;
-+ u32 v = ithc->config.fw_version;
-+ return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff);
-+}
-+static DEVICE_ATTR_RO(fw_version);
-+
-+static const struct attribute_group *ithc_attribute_groups[] = {
-+ &(const struct attribute_group){
-+ .name = DEVNAME,
-+ .attrs = (struct attribute *[]){
-+ &dev_attr_vendor.attr,
-+ &dev_attr_product.attr,
-+ &dev_attr_revision.attr,
-+ &dev_attr_fw_version.attr,
-+ NULL
-+ },
-+ },
-+ NULL
-+};
-+
-+// HID setup
-+
-+static int ithc_hid_start(struct hid_device *hdev) { return 0; }
-+static void ithc_hid_stop(struct hid_device *hdev) { }
-+static int ithc_hid_open(struct hid_device *hdev) { return 0; }
-+static void ithc_hid_close(struct hid_device *hdev) { }
-+
-+static int ithc_hid_parse(struct hid_device *hdev)
-+{
-+ struct ithc *ithc = hdev->driver_data;
-+ u64 val = 0;
-+ WRITE_ONCE(ithc->hid_parse_done, false);
-+ for (int retries = 0; ; retries++) {
-+ CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val);
-+ if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done),
-+ msecs_to_jiffies(200)))
-+ return 0;
-+ if (retries > 5) {
-+ pci_err(ithc->pci, "failed to read report descriptor\n");
-+ return -ETIMEDOUT;
-+ }
-+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n");
-+ }
-+}
-+
-+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf,
-+ size_t len, unsigned char rtype, int reqtype)
-+{
-+ struct ithc *ithc = hdev->driver_data;
-+ if (!buf || !len)
-+ return -EINVAL;
-+ u32 code;
-+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) {
-+ code = DMA_TX_CODE_OUTPUT_REPORT;
-+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) {
-+ code = DMA_TX_CODE_SET_FEATURE;
-+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) {
-+ code = DMA_TX_CODE_GET_FEATURE;
-+ } else {
-+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n",
-+ rtype, reqtype, reportnum);
-+ return -EINVAL;
-+ }
-+ buf[0] = reportnum;
-+
-+ if (reqtype == HID_REQ_GET_REPORT) {
-+ // Prepare for response.
-+ mutex_lock(&ithc->hid_get_feature_mutex);
-+ ithc->hid_get_feature_buf = buf;
-+ ithc->hid_get_feature_size = len;
-+ mutex_unlock(&ithc->hid_get_feature_mutex);
-+
-+ // Transmit 'get feature' request.
-+ int r = CHECK(ithc_dma_tx, ithc, code, 1, buf);
-+ if (!r) {
-+ r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature,
-+ !ithc->hid_get_feature_buf, msecs_to_jiffies(1000));
-+ if (!r)
-+ r = -ETIMEDOUT;
-+ else if (r < 0)
-+ r = -EINTR;
-+ else
-+ r = 0;
-+ }
-+
-+ // If everything went ok, the buffer has been filled with the response data.
-+ // Return the response size.
-+ mutex_lock(&ithc->hid_get_feature_mutex);
-+ ithc->hid_get_feature_buf = NULL;
-+ if (!r)
-+ r = ithc->hid_get_feature_size;
-+ mutex_unlock(&ithc->hid_get_feature_mutex);
-+ return r;
-+ }
-+
-+ // 'Set feature', or 'output report'. These don't have a response.
-+ CHECK_RET(ithc_dma_tx, ithc, code, len, buf);
-+ return 0;
-+}
-+
-+static struct hid_ll_driver ithc_ll_driver = {
-+ .start = ithc_hid_start,
-+ .stop = ithc_hid_stop,
-+ .open = ithc_hid_open,
-+ .close = ithc_hid_close,
-+ .parse = ithc_hid_parse,
-+ .raw_request = ithc_hid_raw_request,
-+};
-+
-+static void ithc_hid_devres_release(struct device *dev, void *res)
-+{
-+ struct hid_device **hidm = res;
-+ if (*hidm)
-+ hid_destroy_device(*hidm);
-+}
-+
-+static int ithc_hid_init(struct ithc *ithc)
-+{
-+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL);
-+ if (!hidm)
-+ return -ENOMEM;
-+ devres_add(&ithc->pci->dev, hidm);
-+ struct hid_device *hid = hid_allocate_device();
-+ if (IS_ERR(hid))
-+ return PTR_ERR(hid);
-+ *hidm = hid;
-+
-+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name));
-+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys));
-+ hid->ll_driver = &ithc_ll_driver;
-+ hid->bus = BUS_PCI;
-+ hid->vendor = ithc->config.vendor_id;
-+ hid->product = ithc->config.product_id;
-+ hid->version = 0x100;
-+ hid->dev.parent = &ithc->pci->dev;
-+ hid->driver_data = ithc;
-+
-+ ithc->hid = hid;
-+ return 0;
-+}
-+
-+// Interrupts/polling
-+
-+static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t)
-+{
-+ struct ithc *ithc = container_of(t, struct ithc, activity_start_timer);
-+ ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC);
-+ return HRTIMER_NORESTART;
-+}
-+
-+static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t)
-+{
-+ struct ithc *ithc = container_of(t, struct ithc, activity_end_timer);
-+ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-+ return HRTIMER_NORESTART;
-+}
-+
-+void ithc_set_active(struct ithc *ithc, unsigned int duration_us)
-+{
-+ if (ithc_dma_latency_us < 0)
-+ return;
-+ // When CPU usage is very low, the CPU can enter various low power states (C2-C10).
-+ // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be
-+ // set when this happens. The amount of truncated messages can become very high, resulting
-+ // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency
-+ // QoS request to prevent the CPU from entering low power states during touch interactions.
-+ cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us);
-+ hrtimer_start_range_ns(&ithc->activity_end_timer,
-+ ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL);
-+}
-+
-+static int ithc_set_device_enabled(struct ithc *ithc, bool enable)
-+{
-+ u32 x = ithc->config.touch_cfg =
-+ (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 |
-+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0);
-+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE,
-+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x);
-+}
-+
-+static void ithc_disable_interrupts(struct ithc *ithc)
-+{
-+ writel(0, &ithc->regs->error_control);
-+ bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0);
-+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
-+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
-+ bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0);
-+}
-+
-+static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel)
-+{
-+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA,
-+ &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_process(struct ithc *ithc)
-+{
-+ ithc_log_regs(ithc);
-+
-+ bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
-+ bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
-+
-+ // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer
-+ ktime_t t = ktime_get();
-+ ktime_t dt = ktime_sub(t, ithc->last_rx_time);
-+ if (rx0 || rx1) {
-+ ithc->last_rx_time = t;
-+ if (dt > ms_to_ktime(100)) {
-+ ithc->cur_rx_seq_count = 0;
-+ ithc->cur_rx_seq_errors = 0;
-+ }
-+ ithc->cur_rx_seq_count++;
-+ if (!ithc_use_polling && ithc_dma_latency_us >= 0) {
-+ // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below)
-+ cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-+ hrtimer_try_to_cancel(&ithc->activity_end_timer);
-+ }
-+ }
-+
-+ // Read and clear error bits
-+ u32 err = readl(&ithc->regs->error_flags);
-+ if (err) {
-+ writel(err, &ithc->regs->error_flags);
-+ if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT)
-+ pci_err(ithc->pci, "error flags: 0x%08x\n", err);
-+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) {
-+ // Only log an error if we see a significant number of these errors.
-+ ithc->cur_rx_seq_errors++;
-+ if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10)
-+ pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n",
-+ ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt));
-+ }
-+ }
-+
-+ // 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);
-+ }
-+
-+ // 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)
-+{
-+ 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.
-+ 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;
-+}
-+
-+// 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)
-+{
-+ ithc_log_regs(ithc);
-+ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0;
-+ ithc_disable(ithc);
-+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY);
-+
-+ // Since we don't yet know which SPI config the device wants, use default speed and mode
-+ // initially for reading config data.
-+ ithc_set_spi_config(ithc, 10, 0);
-+
-+ // Setting the following bit seems to make reading the config more reliable.
-+ bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000);
-+
-+ // If the device was previously enabled, wait a bit to make sure it's fully shut down.
-+ if (was_enabled)
-+ if (msleep_interruptible(100))
-+ return -EINTR;
-+
-+ // Take the touch device out of reset.
-+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
-+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0);
-+ for (int retries = 0; ; retries++) {
-+ ithc_log_regs(ithc);
-+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET);
-+ if (!waitl(ithc, &ithc->regs->state, 0xf, 2))
-+ break;
-+ if (retries > 5) {
-+ pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state));
-+ return -ETIMEDOUT;
-+ }
-+ pci_warn(ithc->pci, "invalid state, retrying reset\n");
-+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
-+ if (msleep_interruptible(1000))
-+ return -EINTR;
-+ }
-+ ithc_log_regs(ithc);
-+
-+ // Waiting for the following status bit makes reading config much more reliable,
-+ // however the official driver does not seem to do this...
-+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4);
-+
-+ // Read configuration data.
-+ for (int retries = 0; ; retries++) {
-+ ithc_log_regs(ithc);
-+ memset(&ithc->config, 0, sizeof(ithc->config));
-+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config);
-+ u32 *p = (void *)&ithc->config;
-+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
-+ if (ithc_is_config_valid(ithc))
-+ break;
-+ if (retries > 10) {
-+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n",
-+ ithc->config.device_id);
-+ return -EIO;
-+ }
-+ pci_warn(ithc->pci, "failed to read config, retrying\n");
-+ if (msleep_interruptible(100))
-+ return -EINTR;
-+ }
-+ ithc_log_regs(ithc);
-+
-+ // Apply SPI config and enable touch device.
-+ CHECK_RET(ithc_set_spi_config, ithc,
-+ DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config),
-+ DEVCFG_SPI_MODE(ithc->config.spi_config));
-+ CHECK_RET(ithc_set_device_enabled, ithc, true);
-+ ithc_log_regs(ithc);
-+ return 0;
-+}
-+
-+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);
-+ CHECK(ithc_set_device_enabled, ithc, false);
-+ ithc_disable(ithc);
-+ hrtimer_cancel(&ithc->activity_start_timer);
-+ hrtimer_cancel(&ithc->activity_end_timer);
-+ cpu_latency_qos_remove_request(&ithc->activity_qos);
-+
-+ // Clear DMA config.
-+ for (unsigned int i = 0; i < 2; i++) {
-+ 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));
-+ 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);
-+
-+ // 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);
-+ CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups);
-+ 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);
-+
-+ cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-+ hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-+ ithc->activity_start_timer.function = ithc_activity_start_timer_callback;
-+ hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-+ ithc->activity_end_timer.function = ithc_activity_end_timer_callback;
-+
-+ // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are
-+ // disabled BEFORE the buffers are freed.
-+ CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc);
-+
-+ CHECK_RET(ithc_hid_init, ithc);
-+
-+ // Start polling/IRQ.
-+ if (ithc_use_polling) {
-+ pci_info(pci, "using polling instead of irq\n");
-+ // 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);
-+
-+ CHECK(ithc_debug_init, 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,
-+ },
-+ //.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)
-+{
-+ return pci_register_driver(&ithc_driver);
-+}
-+
-+static void __exit ithc_exit(void)
-+{
-+ pci_unregister_driver(&ithc_driver);
-+}
-+
-+module_init(ithc_init);
-+module_exit(ithc_exit);
-+
-diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c
-new file mode 100644
-index 0000000000000..e058721886e37
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-regs.c
-@@ -0,0 +1,96 @@
-+// 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)
-+{
-+ 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);
-+ 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);
-+ 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);
-+ return -ETIMEDOUT;
-+ }
-+ pci_dbg(ithc->pci, "done waiting\n");
-+ return 0;
-+}
-+
-+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;
-+ 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)
-+{
-+ 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;
-+
-+ // 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 0000000000000..d4007d9e2bacc
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-regs.h
-@@ -0,0 +1,189 @@
-+/* 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)
-+#define CONTROL_READY BIT(29)
-+
-+#define SPI_CONFIG_MODE(x) (((x) & 3) << 2)
-+#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4)
-+#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18)
-+#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode?
-+
-+#define 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 DMA_RX_CONTROL_ENABLE BIT(0)
-+#define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only?
-+#define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only?
-+#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only?
-+#define DMA_RX_CONTROL_IRQ_DATA BIT(5)
-+
-+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only?
-+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices
-+
-+#define DMA_RX_WRAP_FLAG BIT(7)
-+
-+#define DMA_RX_STATUS_ERROR BIT(3)
-+#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms)
-+#define DMA_RX_STATUS_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 {
-+ /* 0000 */ u32 _unknown_0000[1024];
-+ /* 1000 */ u32 _unknown_1000;
-+ /* 1004 */ u32 _unknown_1004;
-+ /* 1008 */ u32 control_bits;
-+ /* 100c */ u32 _unknown_100c;
-+ /* 1010 */ u32 spi_config;
-+ /* 1014 */ u32 _unknown_1014[3];
-+ /* 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
-+ } dma_tx;
-+ /* 10a0 */ u32 _unknown_10a0[7];
-+ /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET
-+ /* 10c0 */ u32 _unknown_10c0[8];
-+ /* 10e0 */ u32 _unknown_10e0_counters[3];
-+ /* 10ec */ u32 _unknown_10ec[5];
-+ 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 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related
-+ /* 112c/122c */ u32 _unknown_112c;
-+ /* 1130/1230 */ u64 _unknown_1130_guc_addr;
-+ /* 1138/1238 */ u32 _unknown_1138_guc;
-+ /* 113c/123c */ u32 _unknown_113c;
-+ /* 1140/1240 */ u32 _unknown_1140_guc;
-+ /* 1144/1244 */ u32 _unknown_1144[23];
-+ /* 11a0/12a0 */ u32 _unknown_11a0_counters[6];
-+ /* 11b8/12b8 */ u32 _unknown_11b8[18];
-+ } dma_rx[2];
-+};
-+static_assert(sizeof(struct ithc_registers) == 0x1300);
-+
-+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6)
-+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6)
-+
-+#define DEVCFG_TOUCH_MASK 0x3f
-+#define DEVCFG_TOUCH_ENABLE BIT(0)
-+#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1)
-+#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2)
-+#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3)
-+#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4)
-+#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5)
-+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6)
-+
-+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC"
-+
-+#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode?
-+#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3)
-+#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f)
-+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat
-+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7)
-+#define DEVCFG_SPI_UNKNOWN_25 BIT(25)
-+#define DEVCFG_SPI_UNKNOWN_26 BIT(26)
-+#define DEVCFG_SPI_UNKNOWN_27 BIT(27)
-+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this
-+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this?
-+
-+struct ithc_device_config { // (Example values are from an SP7+.)
-+ u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET)
-+ u32 _unknown_04; // 04 = 0x00000000
-+ u32 dma_buf_sizes; // 08 = 0x000a00ff
-+ u32 touch_cfg; // 0c = 0x0000001c
-+ u32 _unknown_10; // 10 = 0x0000001c
-+ u32 device_id; // 14 = 0x43495424 = "$TIC"
-+ u32 spi_config; // 18 = 0xfda00a2e
-+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp.
-+ u16 product_id; // 1e = 0x0c1a
-+ u32 revision; // 20 = 0x00000001
-+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices)
-+ u32 _unknown_28; // 28 = 0x00000000
-+ u32 fw_mode; // 2c = 0x00000000 (for fw update?)
-+ u32 _unknown_30; // 30 = 0x00000000
-+ u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?)
-+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET)
-+ u32 _unknown_3c; // 3c = 0x00000002
-+};
-+
-+void bitsl(__iomem u32 *reg, u32 mask, u32 val);
-+void bitsb(__iomem u8 *reg, u8 mask, u8 val);
-+#define bitsl_set(reg, x) bitsl(reg, x, x)
-+#define bitsb_set(reg, x) bitsb(reg, x, x)
-+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val);
-+int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val);
-+int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode);
-+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 0000000000000..028e55a4ec53e
---- /dev/null
-+++ b/drivers/hid/ithc/ithc.h
-@@ -0,0 +1,67 @@
-+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-+
-+#include <linux/module.h>
-+#include <linux/input.h>
-+#include <linux/hid.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/highmem.h>
-+#include <linux/pci.h>
-+#include <linux/io-64-nonatomic-lo-hi.h>
-+#include <linux/iopoll.h>
-+#include <linux/delay.h>
-+#include <linux/kthread.h>
-+#include <linux/miscdevice.h>
-+#include <linux/debugfs.h>
-+#include <linux/poll.h>
-+#include <linux/timer.h>
-+#include <linux/pm_qos.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
-+
-+struct ithc;
-+
-+#include "ithc-regs.h"
-+#include "ithc-dma.h"
-+
-+struct ithc {
-+ char phys[32];
-+ struct pci_dev *pci;
-+ int irq;
-+ struct task_struct *poll_thread;
-+
-+ struct pm_qos_request activity_qos;
-+ struct hrtimer activity_start_timer;
-+ struct hrtimer activity_end_timer;
-+ ktime_t last_rx_time;
-+ unsigned int cur_rx_seq_count;
-+ unsigned int cur_rx_seq_errors;
-+
-+ struct hid_device *hid;
-+ bool hid_parse_done;
-+ wait_queue_head_t wait_hid_parse;
-+ wait_queue_head_t wait_hid_get_feature;
-+ struct mutex hid_get_feature_mutex;
-+ void *hid_get_feature_buf;
-+ size_t hid_get_feature_size;
-+
-+ struct ithc_registers __iomem *regs;
-+ struct ithc_registers *prev_regs; // for debugging
-+ struct ithc_device_config config;
-+ struct ithc_dma_rx dma_rx[2];
-+ struct ithc_dma_tx dma_tx;
-+};
-+
-+int ithc_reset(struct ithc *ithc);
-+void ithc_set_active(struct ithc *ithc, unsigned int duration_us);
-+int ithc_debug_init(struct ithc *ithc);
-+void ithc_log_regs(struct ithc *ithc);
-+
---
-2.45.1
-
-From 2537922b2f0c1d0002a2afe6d0fc79695add8e60 Mon Sep 17 00:00:00 2001
-From: quo <tuple@list.ru>
-Date: Fri, 19 Apr 2024 22:11:09 +0200
-Subject: [PATCH] hid: ithc: Update from quo/ithc-linux
-
- - Added QuickSPI support for Surface Laptop Studio 2
- - Use Latency Tolerance Reporting instead of manual CPU latency adjustments
-
-Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31
-
-Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
-Patchset: ithc
----
- drivers/hid/ithc/Kbuild | 2 +-
- drivers/hid/ithc/ithc-debug.c | 33 +-
- drivers/hid/ithc/ithc-debug.h | 7 +
- drivers/hid/ithc/ithc-dma.c | 125 ++-----
- drivers/hid/ithc/ithc-dma.h | 24 +-
- drivers/hid/ithc/ithc-hid.c | 207 +++++++++++
- drivers/hid/ithc/ithc-hid.h | 32 ++
- drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++
- drivers/hid/ithc/ithc-legacy.h | 8 +
- drivers/hid/ithc/ithc-main.c | 386 ++++-----------------
- drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++
- drivers/hid/ithc/ithc-quickspi.h | 39 +++
- drivers/hid/ithc/ithc-regs.c | 72 +++-
- drivers/hid/ithc/ithc-regs.h | 143 ++++----
- drivers/hid/ithc/ithc.h | 71 ++--
- 15 files changed, 1441 insertions(+), 538 deletions(-)
- create mode 100644 drivers/hid/ithc/ithc-debug.h
- create mode 100644 drivers/hid/ithc/ithc-hid.c
- create mode 100644 drivers/hid/ithc/ithc-hid.h
- create mode 100644 drivers/hid/ithc/ithc-legacy.c
- create mode 100644 drivers/hid/ithc/ithc-legacy.h
- create mode 100644 drivers/hid/ithc/ithc-quickspi.c
- create mode 100644 drivers/hid/ithc/ithc-quickspi.h
-
-diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild
-index aea83f2ac07b4..4937ba1312973 100644
---- a/drivers/hid/ithc/Kbuild
-+++ b/drivers/hid/ithc/Kbuild
-@@ -1,6 +1,6 @@
- obj-$(CONFIG_HID_ITHC) := ithc.o
-
--ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o
-+ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o
-
- ccflags-y := -std=gnu11 -Wno-declaration-after-statement
-
-diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c
-index 1f1f1e33f2e5a..2d8c6afe99663 100644
---- a/drivers/hid/ithc/ithc-debug.c
-+++ b/drivers/hid/ithc/ithc-debug.c
-@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si
- case 'd': // dma command: cmd len data...
- // get report descriptor: d 7 8 0 0
- // enable multitouch: d 3 2 0x0105
-- if (n < 2 || a[1] > (n - 2) * 4)
-+ if (n < 1)
- return -EINVAL;
-- pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]);
-- if (ithc_dma_tx(ithc, a[0], a[1], a + 2))
-+ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4);
-+ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a };
-+ if (ithc_dma_tx(ithc, &data))
- pci_err(ithc->pci, "dma tx failed\n");
- break;
- default:
-@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si
- return len;
- }
-
-+static struct dentry *dbg_dir;
-+
-+void __init ithc_debug_init_module(void)
-+{
-+ struct dentry *d = debugfs_create_dir(DEVNAME, NULL);
-+ if (IS_ERR(d))
-+ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d));
-+ else
-+ dbg_dir = d;
-+}
-+
-+void __exit ithc_debug_exit_module(void)
-+{
-+ debugfs_remove_recursive(dbg_dir);
-+ dbg_dir = NULL;
-+}
-+
- static const struct file_operations ithc_debugfops_cmd = {
- .owner = THIS_MODULE,
- .write = ithc_debugfs_cmd_write,
-@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = {
- static void ithc_debugfs_devres_release(struct device *dev, void *res)
- {
- struct dentry **dbgm = res;
-- if (*dbgm)
-- debugfs_remove_recursive(*dbgm);
-+ debugfs_remove_recursive(*dbgm);
- }
-
--int ithc_debug_init(struct ithc *ithc)
-+int ithc_debug_init_device(struct ithc *ithc)
- {
-+ if (!dbg_dir)
-+ return -ENOENT;
- struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL);
- if (!dbgm)
- return -ENOMEM;
- devres_add(&ithc->pci->dev, dbgm);
-- struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL);
-+ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir);
- if (IS_ERR(dbg))
- return PTR_ERR(dbg);
- *dbgm = dbg;
-diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h
-new file mode 100644
-index 0000000000000..38c53d916bdb5
---- /dev/null
-+++ b/drivers/hid/ithc/ithc-debug.h
-@@ -0,0 +1,7 @@
-+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-+
-+void ithc_debug_init_module(void);
-+void ithc_debug_exit_module(void);
-+int ithc_debug_init_device(struct ithc *ithc);
-+void ithc_log_regs(struct ithc *ithc);
-+
-diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c
-index ffb8689b8a780..bf4eab33062b0 100644
---- a/drivers/hid/ithc/ithc-dma.c
-+++ b/drivers/hid/ithc/ithc-dma.c
-@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel)
- mutex_init(&rx->mutex);
-
- // Allocate buffers.
-- u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes);
-- unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE;
-+ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE;
- pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n",
-- NUM_RX_BUF, buf_size, num_pages);
-+ NUM_RX_BUF, ithc->max_rx_size, num_pages);
- CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE);
- for (unsigned int i = 0; i < NUM_RX_BUF; i++)
- CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]);
-@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc)
- mutex_init(&tx->mutex);
-
- // Allocate buffers.
-- tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes);
-- unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE;
-+ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE;
- pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n",
-- tx->max_size, num_pages);
-+ ithc->max_tx_size, num_pages);
- CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE);
- CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf);
-
-@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc)
- return 0;
- }
-
--static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data,
-- u8 channel, u8 buf)
--{
-- if (buf >= NUM_RX_BUF) {
-- pci_err(ithc->pci, "invalid dma ringbuffer index\n");
-- return -EINVAL;
-- }
-- u32 len = data->data_size;
-- struct ithc_dma_rx_header *hdr = data->addr;
-- u8 *hiddata = (void *)(hdr + 1);
-- if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) {
-- // The THC sends a reset request when we need to reinitialize the device.
-- // This usually only happens if we send an invalid command or put the device
-- // in a bad state.
-- CHECK(ithc_reset, ithc);
-- } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) {
-- if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
-- // When the CPU enters a low power state during DMA, we can get truncated
-- // messages. For Surface devices, this will typically be a single touch
-- // report that is only 1 byte, or a multitouch report that is 257 bytes.
-- // See also ithc_set_active().
-- } else {
-- pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n",
-- channel, buf, len, hdr->code, hdr->data_size);
-- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
-- hdr, min(len, 0x400u), 0);
-- }
-- } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) {
-- // Response to a 'get report descriptor' request.
-- // The actual descriptor is preceded by 8 nul bytes.
-- CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8);
-- WRITE_ONCE(ithc->hid_parse_done, true);
-- wake_up(&ithc->wait_hid_parse);
-- } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) {
-- // Standard HID input report containing touch data.
-- CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1);
-- } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) {
-- // Response to a 'get feature' request.
-- bool done = false;
-- mutex_lock(&ithc->hid_get_feature_mutex);
-- if (ithc->hid_get_feature_buf) {
-- if (hdr->data_size < ithc->hid_get_feature_size)
-- ithc->hid_get_feature_size = hdr->data_size;
-- memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size);
-- ithc->hid_get_feature_buf = NULL;
-- done = true;
-- }
-- mutex_unlock(&ithc->hid_get_feature_mutex);
-- if (done) {
-- wake_up(&ithc->wait_hid_get_feature);
-- } else {
-- // Received data without a matching request, or the request already
-- // timed out. (XXX What's the correct thing to do here?)
-- CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT,
-- hiddata, hdr->data_size, 1);
-- }
-- } else {
-- pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n",
-- channel, buf, len, hdr->code);
-- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
-- hdr, min(len, 0x400u), 0);
-- }
-- return 0;
--}
--
- static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
- {
- // Process all filled RX buffers from the ringbuffer.
-@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel)
- rx->num_received = ++n;
-
- // process data
-- CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail);
-+ struct ithc_data d;
-+ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx)
-+ (ithc, b->addr, b->data_size, &d) < 0) {
-+ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n",
-+ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr);
-+ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1,
-+ b->addr, min(b->data_size, 0x400u), 0);
-+ } else {
-+ ithc_hid_process_data(ithc, &d);
-+ }
-
- // give the buffer back to the device
- CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail);
-@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel)
- return ret;
- }
-
--static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
-+static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data)
- {
-- ithc_set_active(ithc, 100 * USEC_PER_MSEC);
--
- // Send a single TX buffer to the THC.
-- pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize);
-- struct ithc_dma_tx_header *hdr;
-- // Data must be padded to next 4-byte boundary.
-- u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0;
-- unsigned int fullsize = sizeof(*hdr) + datasize + padding;
-- if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE)
-- return -EINVAL;
-+ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size);
- CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
-
- // Fill the TX buffer with header and data.
-- ithc->dma_tx.buf.data_size = fullsize;
-- hdr = ithc->dma_tx.buf.addr;
-- hdr->code = cmdcode;
-- hdr->data_size = datasize;
-- u8 *dest = (void *)(hdr + 1);
-- memcpy(dest, data, datasize);
-- dest += datasize;
-- for (u8 p = 0; p < padding; p++)
-- *dest++ = 0;
-+ ssize_t sz;
-+ if (data->type == ITHC_DATA_RAW) {
-+ sz = min(data->size, ithc->max_tx_size);
-+ memcpy(ithc->dma_tx.buf.addr, data->data, sz);
-+ } else {
-+ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx)
-+ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size);
-+ }
-+ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz;
- CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0);
-+ if (sz < 0) {
-+ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n",
-+ data->type, data->size, (int)sz);
-+ return -EINVAL;
-+ }
-
- // Let the THC process the buffer.
- bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND);
-@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo
- writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status);
- return 0;
- }
--int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data)
-+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data)
- {
- mutex_lock(&ithc->dma_tx.mutex);
-- int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data);
-+ int ret = ithc_dma_tx_unlocked(ithc, data);
- mutex_unlock(&ithc->dma_tx.mutex);
- return ret;
- }
-diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h
-index 93652e4476bf8..1749a5819b3e7 100644
---- a/drivers/hid/ithc/ithc-dma.h
-+++ b/drivers/hid/ithc/ithc-dma.h
-@@ -11,27 +11,6 @@ struct ithc_phys_region_desc {
- u32 unused;
- };
-
--#define DMA_RX_CODE_INPUT_REPORT 3
--#define DMA_RX_CODE_FEATURE_REPORT 4
--#define DMA_RX_CODE_REPORT_DESCRIPTOR 5
--#define DMA_RX_CODE_RESET 7
--
--struct ithc_dma_rx_header {
-- u32 code;
-- u32 data_size;
-- u32 _unknown[14];
--};
--
--#define DMA_TX_CODE_SET_FEATURE 3
--#define DMA_TX_CODE_GET_FEATURE 4
--#define DMA_TX_CODE_OUTPUT_REPORT 5
--#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7
--
--struct ithc_dma_tx_header {
-- u32 code;
-- u32 data_size;
--};
--
- struct ithc_dma_prd_buffer {
- void *addr;
- dma_addr_t dma_addr;
-@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer {
-
- struct ithc_dma_tx {
- struct mutex mutex;
-- u32 max_size;
- struct ithc_dma_prd_buffer prds;
- struct ithc_dma_data_buffer buf;
- };
-@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel);
- void ithc_dma_rx_enable(struct ithc *ithc, u8 channel);
- int ithc_dma_tx_init(struct ithc *ithc);
- int ithc_dma_rx(struct ithc *ithc, u8 channel);
--int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata);
+int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data);
-
++
diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c
new file mode 100644
-index 0000000000000..065646ab499ef
+index 000000000000..065646ab499e
--- /dev/null
+++ b/drivers/hid/ithc/ithc-hid.c
@@ -0,0 +1,207 @@
@@ -6339,7 +4788,7 @@ index 0000000000000..065646ab499ef
+
diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h
new file mode 100644
-index 0000000000000..599eb912c8c84
+index 000000000000..599eb912c8c8
--- /dev/null
+++ b/drivers/hid/ithc/ithc-hid.h
@@ -0,0 +1,32 @@
@@ -6377,10 +4826,10 @@ index 0000000000000..599eb912c8c84
+
diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c
new file mode 100644
-index 0000000000000..5c1da11e3f1d2
+index 000000000000..8883987fb352
--- /dev/null
+++ b/drivers/hid/ithc/ithc-legacy.c
-@@ -0,0 +1,252 @@
+@@ -0,0 +1,254 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+#include "ithc.h"
@@ -6465,8 +4914,10 @@ index 0000000000000..5c1da11e3f1d2
+ // Setting the following bit seems to make reading the config more reliable.
+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31);
+
-+ // Setting this bit may be necessary on some ADL devices.
++ // 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:
@@ -6635,7 +5086,7 @@ index 0000000000000..5c1da11e3f1d2
+
diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h
new file mode 100644
-index 0000000000000..28d6924620722
+index 000000000000..28d692462072
--- /dev/null
+++ b/drivers/hid/ithc/ithc-legacy.h
@@ -0,0 +1,8 @@
@@ -6648,379 +5099,178 @@ index 0000000000000..28d6924620722
+ size_t maxlen);
+
diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c
-index 87ed4aa70fda0..2acf02e41d40f 100644
---- a/drivers/hid/ithc/ithc-main.c
+new file mode 100644
+index 000000000000..ac56c253674b
+--- /dev/null
+++ b/drivers/hid/ithc/ithc-main.c
-@@ -5,28 +5,6 @@
- MODULE_DESCRIPTION("Intel Touch Host Controller driver");
- MODULE_LICENSE("Dual BSD/GPL");
-
--// Lakefield
--#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0
--#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1
--// Tiger Lake
--#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0
--#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1
--#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0
--#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1
--// Alder Lake
--#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8
--#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9
--#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0
--#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1
--#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0
--#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1
--// Raptor Lake
--#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58
--#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59
--// Meteor Lake
--#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48
--#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a
--
- static const struct pci_device_id ithc_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) },
-@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true;
- module_param_named(rx1, ithc_use_rx1, bool, 0);
- MODULE_PARM_DESC(rx1, "Use DMA RX channel 1");
-
--// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering.
--static int ithc_dma_latency_us = 200;
--module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0);
--MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS");
+@@ -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)");
-
--// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering.
--static unsigned int ithc_dma_early_us = 2000;
--module_param_named(dma_early_us, ithc_dma_early_us, uint, 0);
--MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)");
++
+static int ithc_idle_ltr_us = -1;
+module_param_named(idleltr, ithc_idle_ltr_us, int, 0);
+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)");
-
- static bool ithc_log_regs_enabled = false;
- module_param_named(logregs, ithc_log_regs_enabled, bool, 0);
-@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)");
-
- // Sysfs attributes
-
--static bool ithc_is_config_valid(struct ithc *ithc)
--{
-- return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC;
--}
--
- static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
- {
- struct ithc *ithc = dev_get_drvdata(dev);
-- if (!ithc || !ithc_is_config_valid(ithc))
-+ if (!ithc || !ithc->have_config)
- return -ENODEV;
-- return sprintf(buf, "0x%04x", ithc->config.vendor_id);
-+ return sprintf(buf, "0x%04x", ithc->vendor_id);
- }
- static DEVICE_ATTR_RO(vendor);
- static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf)
- {
- struct ithc *ithc = dev_get_drvdata(dev);
-- if (!ithc || !ithc_is_config_valid(ithc))
-+ if (!ithc || !ithc->have_config)
- return -ENODEV;
-- return sprintf(buf, "0x%04x", ithc->config.product_id);
-+ return sprintf(buf, "0x%04x", ithc->product_id);
- }
- static DEVICE_ATTR_RO(product);
- static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf)
- {
- struct ithc *ithc = dev_get_drvdata(dev);
-- if (!ithc || !ithc_is_config_valid(ithc))
-+ if (!ithc || !ithc->have_config)
- return -ENODEV;
-- return sprintf(buf, "%u", ithc->config.revision);
-+ return sprintf(buf, "%u", ithc->product_rev);
- }
- static DEVICE_ATTR_RO(revision);
--static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf)
--{
-- struct ithc *ithc = dev_get_drvdata(dev);
-- if (!ithc || !ithc_is_config_valid(ithc))
-- return -ENODEV;
-- u32 v = ithc->config.fw_version;
-- return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff);
--}
--static DEVICE_ATTR_RO(fw_version);
-
- static const struct attribute_group *ithc_attribute_groups[] = {
- &(const struct attribute_group){
-@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = {
- &dev_attr_vendor.attr,
- &dev_attr_product.attr,
- &dev_attr_revision.attr,
-- &dev_attr_fw_version.attr,
- NULL
- },
- },
- NULL
- };
-
--// HID setup
--
--static int ithc_hid_start(struct hid_device *hdev) { return 0; }
--static void ithc_hid_stop(struct hid_device *hdev) { }
--static int ithc_hid_open(struct hid_device *hdev) { return 0; }
--static void ithc_hid_close(struct hid_device *hdev) { }
--
--static int ithc_hid_parse(struct hid_device *hdev)
--{
-- struct ithc *ithc = hdev->driver_data;
-- u64 val = 0;
-- WRITE_ONCE(ithc->hid_parse_done, false);
-- for (int retries = 0; ; retries++) {
-- CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val);
-- if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done),
-- msecs_to_jiffies(200)))
-- return 0;
-- if (retries > 5) {
-- pci_err(ithc->pci, "failed to read report descriptor\n");
-- return -ETIMEDOUT;
-- }
-- pci_warn(ithc->pci, "failed to read report descriptor, retrying\n");
-- }
--}
--
--static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf,
-- size_t len, unsigned char rtype, int reqtype)
--{
-- struct ithc *ithc = hdev->driver_data;
-- if (!buf || !len)
-- return -EINVAL;
-- u32 code;
-- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) {
-- code = DMA_TX_CODE_OUTPUT_REPORT;
-- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) {
-- code = DMA_TX_CODE_SET_FEATURE;
-- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) {
-- code = DMA_TX_CODE_GET_FEATURE;
-- } else {
-- pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n",
-- rtype, reqtype, reportnum);
-- return -EINVAL;
-- }
-- buf[0] = reportnum;
--
-- if (reqtype == HID_REQ_GET_REPORT) {
-- // Prepare for response.
-- mutex_lock(&ithc->hid_get_feature_mutex);
-- ithc->hid_get_feature_buf = buf;
-- ithc->hid_get_feature_size = len;
-- mutex_unlock(&ithc->hid_get_feature_mutex);
--
-- // Transmit 'get feature' request.
-- int r = CHECK(ithc_dma_tx, ithc, code, 1, buf);
-- if (!r) {
-- r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature,
-- !ithc->hid_get_feature_buf, msecs_to_jiffies(1000));
-- if (!r)
-- r = -ETIMEDOUT;
-- else if (r < 0)
-- r = -EINTR;
-- else
-- r = 0;
-- }
--
-- // If everything went ok, the buffer has been filled with the response data.
-- // Return the response size.
-- mutex_lock(&ithc->hid_get_feature_mutex);
-- ithc->hid_get_feature_buf = NULL;
-- if (!r)
-- r = ithc->hid_get_feature_size;
-- mutex_unlock(&ithc->hid_get_feature_mutex);
-- return r;
-- }
--
-- // 'Set feature', or 'output report'. These don't have a response.
-- CHECK_RET(ithc_dma_tx, ithc, code, len, buf);
-- return 0;
--}
--
--static struct hid_ll_driver ithc_ll_driver = {
-- .start = ithc_hid_start,
-- .stop = ithc_hid_stop,
-- .open = ithc_hid_open,
-- .close = ithc_hid_close,
-- .parse = ithc_hid_parse,
-- .raw_request = ithc_hid_raw_request,
--};
--
--static void ithc_hid_devres_release(struct device *dev, void *res)
--{
-- struct hid_device **hidm = res;
-- if (*hidm)
-- hid_destroy_device(*hidm);
--}
--
--static int ithc_hid_init(struct ithc *ithc)
--{
-- struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL);
-- if (!hidm)
-- return -ENOMEM;
-- devres_add(&ithc->pci->dev, hidm);
-- struct hid_device *hid = hid_allocate_device();
-- if (IS_ERR(hid))
-- return PTR_ERR(hid);
-- *hidm = hid;
--
-- strscpy(hid->name, DEVFULLNAME, sizeof(hid->name));
-- strscpy(hid->phys, ithc->phys, sizeof(hid->phys));
-- hid->ll_driver = &ithc_ll_driver;
-- hid->bus = BUS_PCI;
-- hid->vendor = ithc->config.vendor_id;
-- hid->product = ithc->config.product_id;
-- hid->version = 0x100;
-- hid->dev.parent = &ithc->pci->dev;
-- hid->driver_data = ithc;
--
-- ithc->hid = hid;
-- return 0;
--}
--
- // Interrupts/polling
-
--static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t)
--{
-- struct ithc *ithc = container_of(t, struct ithc, activity_start_timer);
-- ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC);
-- return HRTIMER_NORESTART;
--}
--
--static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t)
--{
-- struct ithc *ithc = container_of(t, struct ithc, activity_end_timer);
-- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-- return HRTIMER_NORESTART;
--}
--
--void ithc_set_active(struct ithc *ithc, unsigned int duration_us)
--{
-- if (ithc_dma_latency_us < 0)
-- return;
-- // When CPU usage is very low, the CPU can enter various low power states (C2-C10).
-- // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be
-- // set when this happens. The amount of truncated messages can become very high, resulting
-- // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency
-- // QoS request to prevent the CPU from entering low power states during touch interactions.
-- cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us);
-- hrtimer_start_range_ns(&ithc->activity_end_timer,
-- ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL);
--}
--
--static int ithc_set_device_enabled(struct ithc *ithc, bool enable)
--{
-- u32 x = ithc->config.touch_cfg =
-- (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 |
-- (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0);
-- return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE,
-- offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x);
--}
--
- static void ithc_disable_interrupts(struct ithc *ithc)
- {
- writel(0, &ithc->regs->error_control);
- bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0);
-- bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
-- bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0);
++
++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_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA,
++ 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);
- }
-
-@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc)
- {
- ithc_log_regs(ithc);
-
-+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer.
-+ // It does not appear to automatically go back to idle, so we switch it back here, since
-+ // the DMA transfer should be complete.
++ &ithc->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);
++}
+
- bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
- bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0;
-
-- // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer
-- ktime_t t = ktime_get();
-- ktime_t dt = ktime_sub(t, ithc->last_rx_time);
-- if (rx0 || rx1) {
-- ithc->last_rx_time = t;
-- if (dt > ms_to_ktime(100)) {
-- ithc->cur_rx_seq_count = 0;
-- ithc->cur_rx_seq_errors = 0;
-- }
-- ithc->cur_rx_seq_count++;
-- if (!ithc_use_polling && ithc_dma_latency_us >= 0) {
-- // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below)
-- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-- hrtimer_try_to_cancel(&ithc->activity_end_timer);
-- }
-- }
--
- // Read and clear error bits
- u32 err = readl(&ithc->regs->error_flags);
- if (err) {
- writel(err, &ithc->regs->error_flags);
- if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT)
- pci_err(ithc->pci, "error flags: 0x%08x\n", err);
-- if (err & ERROR_FLAG_DMA_RX_TIMEOUT) {
-- // Only log an error if we see a significant number of these errors.
-- ithc->cur_rx_seq_errors++;
-- if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10)
-- pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n",
-- ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt));
-- }
++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
-@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc)
- ithc_dma_rx(ithc, 1);
- }
-
-- // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT
-- if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) {
-- ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us));
-- hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS);
-- }
--
- ithc_log_regs(ithc);
- }
-
-@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg)
- ithc_process(ithc);
- // Decrease polling interval to 20ms if we received data, otherwise slowly
- // increase it up to 200ms.
-- if (n != ithc->dma_rx[1].num_received) {
-- ithc_set_active(ithc, 100 * USEC_PER_MSEC);
-- sleep = 20;
-- } else {
-- sleep = min(200u, sleep + (sleep >> 4) + 1);
-- }
++ }
++
++ // 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;
-@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc)
-
- static int ithc_init_device(struct ithc *ithc)
- {
++ 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);
@@ -7031,49 +5281,24 @@ index 87ed4aa70fda0..2acf02e41d40f 100644
+ ithc->use_quickspi = cfg.has_config;
+
+ // Shut down device
- ithc_log_regs(ithc);
- bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0;
- ithc_disable(ithc);
- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY);
--
-- // Since we don't yet know which SPI config the device wants, use default speed and mode
-- // initially for reading config data.
-- ithc_set_spi_config(ithc, 10, 0);
--
-- // Setting the following bit seems to make reading the config more reliable.
-- bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000);
+ ithc_log_regs(ithc);
-
- // If the device was previously enabled, wait a bit to make sure it's fully shut down.
- if (was_enabled)
- if (msleep_interruptible(100))
- return -EINTR;
-
-- // Take the touch device out of reset.
-- bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0);
-- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0);
-- for (int retries = 0; ; retries++) {
-- ithc_log_regs(ithc);
-- bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET);
-- if (!waitl(ithc, &ithc->regs->state, 0xf, 2))
-- break;
-- if (retries > 5) {
-- pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state));
-- return -ETIMEDOUT;
-- }
-- pci_warn(ithc->pci, "invalid state, retrying reset\n");
-- bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0);
-- if (msleep_interruptible(1000))
-- return -EINTR;
-- }
-- ithc_log_regs(ithc);
++ 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 100us, and idle to 100ms.
++ // 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
-+ : 100 * 1000;
++ : 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;
@@ -7083,137 +5308,239 @@ index 87ed4aa70fda0..2acf02e41d40f 100644
+ CHECK_RET(ithc_quickspi_init, ithc, &cfg);
+ else
+ CHECK_RET(ithc_legacy_init, ithc);
-
-- // Waiting for the following status bit makes reading config much more reliable,
-- // however the official driver does not seem to do this...
-- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4);
--
-- // Read configuration data.
-- for (int retries = 0; ; retries++) {
-- ithc_log_regs(ithc);
-- memset(&ithc->config, 0, sizeof(ithc->config));
-- CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config);
-- u32 *p = (void *)&ithc->config;
-- pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
-- if (ithc_is_config_valid(ithc))
-- break;
-- if (retries > 10) {
-- pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n",
-- ithc->config.device_id);
-- return -EIO;
-- }
-- pci_warn(ithc->pci, "failed to read config, retrying\n");
-- if (msleep_interruptible(100))
-- return -EINTR;
-- }
-- ithc_log_regs(ithc);
--
-- // Apply SPI config and enable touch device.
-- CHECK_RET(ithc_set_spi_config, ithc,
-- DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config),
-- DEVCFG_SPI_MODE(ithc->config.spi_config));
-- CHECK_RET(ithc_set_device_enabled, ithc, true);
-- ithc_log_regs(ithc);
- return 0;
- }
-
-@@ -527,11 +274,11 @@ static void ithc_stop(void *res)
- CHECK(kthread_stop, ithc->poll_thread);
- if (ithc->irq >= 0)
- disable_irq(ithc->irq);
-- CHECK(ithc_set_device_enabled, ithc, false);
++
++ 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);
-- hrtimer_cancel(&ithc->activity_start_timer);
-- hrtimer_cancel(&ithc->activity_end_timer);
-- cpu_latency_qos_remove_request(&ithc->activity_qos);
-
- // Clear DMA config.
- for (unsigned int i = 0; i < 2; i++) {
-@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci)
- ithc->irq = -1;
- ithc->pci = pci;
- snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci));
-- init_waitqueue_head(&ithc->wait_hid_parse);
-- init_waitqueue_head(&ithc->wait_hid_get_feature);
-- mutex_init(&ithc->hid_get_feature_mutex);
- pci_set_drvdata(pci, ithc);
- CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci);
- if (ithc_log_regs_enabled)
-@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci)
-
- // Initialize THC and touch device.
- CHECK_RET(ithc_init_device, ithc);
++ 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);
- CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups);
- if (ithc_use_rx0)
- CHECK_RET(ithc_dma_rx_init, ithc, 0);
-@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci)
- CHECK_RET(ithc_dma_rx_init, ithc, 1);
- CHECK_RET(ithc_dma_tx_init, ithc);
-
-- cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE);
-- hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-- ithc->activity_start_timer.function = ithc_activity_start_timer_callback;
-- hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-- ithc->activity_end_timer.function = ithc_activity_end_timer_callback;
--
- // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are
- // disabled BEFORE the buffers are freed.
- CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc);
-
-- CHECK_RET(ithc_hid_init, ithc);
--
- // Start polling/IRQ.
- if (ithc_use_polling) {
- pci_info(pci, "using polling instead of irq\n");
-@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci)
-
- // hid_add_device() can only be called after irq/polling is started and DMA is enabled,
- // because it calls ithc_hid_parse() which reads the report descriptor via DMA.
-- CHECK_RET(hid_add_device, ithc->hid);
++ 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);
-
-- CHECK(ithc_debug_init, ithc);
++
+ ithc_set_ltr_idle(ithc);
-
- pci_dbg(pci, "started\n");
- return 0;
-@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = {
- .thaw = ithc_thaw,
- .restore = ithc_restore,
- },
++
++ 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,
- //.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)
++{
+ ithc_debug_init_module();
- return pci_register_driver(&ithc_driver);
- }
-
- static void __exit ithc_exit(void)
- {
- pci_unregister_driver(&ithc_driver);
++ 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_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 0000000000000..760e55ead0788
+index 000000000000..e2d1690b8cf8
--- /dev/null
+++ b/drivers/hid/ithc/ithc-quickspi.c
-@@ -0,0 +1,578 @@
+@@ -0,0 +1,607 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
+
+// Some public THC/QuickSPI documentation can be found in:
@@ -7473,6 +5800,14 @@ index 0000000000000..760e55ead0788
+ 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");
@@ -7495,26 +5830,47 @@ index 0000000000000..760e55ead0788
+ // 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)
++ 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);
+
-+ if (cfg->has_read_opcode) {
-+ writeb(cfg->read_opcode, &ithc->regs->read_opcode);
-+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_single);
-+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual);
-+ writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad);
-+ }
-+ if (cfg->has_write_opcode) {
-+ writeb(cfg->write_opcode, &ithc->regs->write_opcode);
-+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_single);
-+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual);
-+ writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad);
++ 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),
@@ -7794,7 +6150,7 @@ index 0000000000000..760e55ead0788
+
diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h
new file mode 100644
-index 0000000000000..74d882f6b2f0a
+index 000000000000..74d882f6b2f0
--- /dev/null
+++ b/drivers/hid/ithc/ithc-quickspi.h
@@ -0,0 +1,39 @@
@@ -7838,51 +6194,69 @@ index 0000000000000..74d882f6b2f0a
+ size_t maxlen);
+
diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c
-index e058721886e37..c0f13506af205 100644
---- a/drivers/hid/ithc/ithc-regs.c
+new file mode 100644
+index 000000000000..c0f13506af20
+--- /dev/null
+++ b/drivers/hid/ithc/ithc-regs.c
-@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val)
-
- int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val)
- {
+@@ -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)) {
++ 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;
- }
++ 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)
- {
++ 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)) {
++ 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;
- }
++ pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n",
++ reg_num(reg), mask, val);
++ return -ETIMEDOUT;
++ }
+ ithc_log_regs(ithc);
- pci_dbg(ithc->pci, "done waiting\n");
- return 0;
- }
-
--int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode)
++ pci_dbg(ithc->pci, "done waiting\n");
++ return 0;
++}
++
+static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale)
- {
-- pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode);
-- if (mode == 3)
-- mode = 2;
++{
+ unsigned int s = 0;
+ u64 v = *ns;
+ while (v > 0x3ff) {
@@ -7934,32 +6308,59 @@ index e058721886e37..c0f13506af205 100644
+ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n",
+ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)),
+ modes[read_mode], modes[write_mode]);
- bitsl(&ithc->regs->spi_config,
-- SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff),
-- SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed));
++ 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 %u\n", command, size, offset);
++ 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;
-
++ 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
-index d4007d9e2bacc..a9d2364546442 100644
---- a/drivers/hid/ithc/ithc-regs.h
+new file mode 100644
+index 000000000000..4f541fe533fa
+--- /dev/null
+++ b/drivers/hid/ithc/ithc-regs.h
-@@ -1,14 +1,34 @@
- /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-
+@@ -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)
@@ -7971,16 +6372,12 @@ index d4007d9e2bacc..a9d2364546442 100644
+#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_QUIESCE BIT(1)
++#define CONTROL_IS_QUIESCED BIT(2)
++#define CONTROL_NRESET BIT(3)
+#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24)
- #define CONTROL_READY BIT(29)
-
--#define SPI_CONFIG_MODE(x) (((x) & 3) << 2)
--#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4)
--#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18)
--#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode?
++#define 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)
@@ -7993,13 +6390,50 @@ index d4007d9e2bacc..a9d2364546442 100644
+#define SPI_MODE_SINGLE 0
+#define SPI_MODE_DUAL 1
+#define SPI_MODE_QUAD 2
-
- #define ERROR_CONTROL_UNKNOWN_0 BIT(0)
- #define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs
-@@ -53,33 +73,71 @@
- #define DMA_TX_STATUS_UNKNOWN_2 BIT(2)
- #define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy?
-
++
++#define 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)
@@ -8021,195 +6455,157 @@ index d4007d9e2bacc..a9d2364546442 100644
+#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27)
+#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28)
+
- #define DMA_RX_CONTROL_ENABLE BIT(0)
- #define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only?
- #define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only?
--#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only?
++#define DMA_RX_CONTROL_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_CONTROL_IRQ_DATA BIT(5)
++
+#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only?
- #define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only?
- #define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices
-
- #define DMA_RX_WRAP_FLAG BIT(7)
-
- #define DMA_RX_STATUS_ERROR BIT(3)
--#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms)
++#define DMA_RX_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 DMA_RX_STATUS_HAVE_DATA BIT(5)
++#define DMA_RX_STATUS_ENABLED BIT(8)
++
+#define INIT_UNKNOWN_GUC_2 BIT(2)
+#define INIT_UNKNOWN_3 BIT(3)
+#define INIT_UNKNOWN_GUC_4 BIT(4)
+#define INIT_UNKNOWN_5 BIT(5)
+#define INIT_UNKNOWN_31 BIT(31)
+
- // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC.
- #define COUNTER_RESET BIT(31)
-
- struct ithc_registers {
-- /* 0000 */ u32 _unknown_0000[1024];
++// 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;
-- /* 1014 */ u32 _unknown_1014[3];
-+ /* 1014 */ u8 read_opcode; // maybe for header?
-+ /* 1015 */ u8 read_opcode_quad;
-+ /* 1016 */ u8 read_opcode_dual;
-+ /* 1017 */ u8 read_opcode_single;
-+ /* 1018 */ u8 write_opcode; // not used?
-+ /* 1019 */ u8 write_opcode_quad;
-+ /* 101a */ u8 write_opcode_dual;
-+ /* 101b */ u8 write_opcode_single;
-+ /* 101c */ u32 _unknown_101c;
- /* 1020 */ u32 error_control;
- /* 1024 */ u32 error_status; // write to clear
- /* 1028 */ u32 error_flags; // write to clear
-@@ -100,12 +158,19 @@ struct ithc_registers {
- /* 109a */ u8 _unknown_109a;
- /* 109b */ u8 num_prds;
- /* 109c */ u32 status; // write to clear
++ /* 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;
-- /* 10a0 */ u32 _unknown_10a0[7];
-- /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET
++ } 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 _unknown_10ec[5];
++ /* 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;
-@@ -120,70 +185,30 @@ struct ithc_registers {
- /* 1118/1218 */ u64 _unknown_1118_guc_addr;
- /* 1120/1220 */ u32 _unknown_1120_guc;
- /* 1124/1224 */ u32 _unknown_1124_guc;
-- /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related
++ 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[23];
++ /* 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);
-
--#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6)
--#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6)
--
--#define DEVCFG_TOUCH_MASK 0x3f
--#define DEVCFG_TOUCH_ENABLE BIT(0)
--#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1)
--#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2)
--#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3)
--#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4)
--#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5)
--#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6)
--
--#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC"
--
--#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode?
--#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3)
--#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f)
--#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat
--#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7)
--#define DEVCFG_SPI_UNKNOWN_25 BIT(25)
--#define DEVCFG_SPI_UNKNOWN_26 BIT(26)
--#define DEVCFG_SPI_UNKNOWN_27 BIT(27)
--#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this
--#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this?
--
--struct ithc_device_config { // (Example values are from an SP7+.)
-- u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET)
-- u32 _unknown_04; // 04 = 0x00000000
-- u32 dma_buf_sizes; // 08 = 0x000a00ff
-- u32 touch_cfg; // 0c = 0x0000001c
-- u32 _unknown_10; // 10 = 0x0000001c
-- u32 device_id; // 14 = 0x43495424 = "$TIC"
-- u32 spi_config; // 18 = 0xfda00a2e
-- u16 vendor_id; // 1c = 0x045e = Microsoft Corp.
-- u16 product_id; // 1e = 0x0c1a
-- u32 revision; // 20 = 0x00000001
-- u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices)
-- u32 _unknown_28; // 28 = 0x00000000
-- u32 fw_mode; // 2c = 0x00000000 (for fw update?)
-- u32 _unknown_30; // 30 = 0x00000000
-- u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?)
-- u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET)
-- u32 _unknown_3c; // 3c = 0x00000002
--};
--
- void bitsl(__iomem u32 *reg, u32 mask, u32 val);
- void bitsb(__iomem u8 *reg, u8 mask, u8 val);
- #define bitsl_set(reg, x) bitsl(reg, x, x)
- #define bitsb_set(reg, x) bitsb(reg, x, x)
- int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val);
- int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val);
--int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode);
++ /* 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);
-
++int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data);
++
diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h
-index 028e55a4ec53e..e90c380444325 100644
---- a/drivers/hid/ithc/ithc.h
+new file mode 100644
+index 000000000000..aec320d4e945
+--- /dev/null
+++ b/drivers/hid/ithc/ithc.h
-@@ -1,20 +1,19 @@
- /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
-
--#include <linux/module.h>
--#include <linux/input.h>
--#include <linux/hid.h>
+@@ -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/dma-mapping.h>
+#include <linux/hid.h>
- #include <linux/highmem.h>
--#include <linux/pci.h>
++#include <linux/highmem.h>
+#include <linux/input.h>
- #include <linux/io-64-nonatomic-lo-hi.h>
- #include <linux/iopoll.h>
--#include <linux/delay.h>
- #include <linux/kthread.h>
- #include <linux/miscdevice.h>
--#include <linux/debugfs.h>
++#include <linux/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/pm_qos.h>
-
- #define DEVNAME "ithc"
- #define DEVFULLNAME "Intel Touch Host Controller"
-@@ -27,10 +26,37 @@
-
- #define NUM_RX_BUF 16
-
++#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
@@ -8230,44 +6626,31 @@ index 028e55a4ec53e..e90c380444325 100644
+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58
+#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59
+// Meteor Lake
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48
-+#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a
++#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"
++struct ithc;
++
++#include "ithc-regs.h"
+#include "ithc-hid.h"
- #include "ithc-dma.h"
++#include "ithc-dma.h"
+#include "ithc-legacy.h"
+#include "ithc-quickspi.h"
+#include "ithc-debug.h"
-
- struct ithc {
- char phys[32];
-@@ -38,30 +64,21 @@ struct ithc {
- int irq;
- struct task_struct *poll_thread;
-
-- struct pm_qos_request activity_qos;
-- struct hrtimer activity_start_timer;
-- struct hrtimer activity_end_timer;
-- ktime_t last_rx_time;
-- unsigned int cur_rx_seq_count;
-- unsigned int cur_rx_seq_errors;
--
-- struct hid_device *hid;
-- bool hid_parse_done;
-- wait_queue_head_t wait_hid_parse;
-- wait_queue_head_t wait_hid_get_feature;
-- struct mutex hid_get_feature_mutex;
-- void *hid_get_feature_buf;
-- size_t hid_get_feature_size;
--
- struct ithc_registers __iomem *regs;
- struct ithc_registers *prev_regs; // for debugging
-- struct ithc_device_config config;
- struct ithc_dma_rx dma_rx[2];
- struct ithc_dma_tx dma_tx;
++
++struct ithc {
++ 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;
@@ -8278,234 +6661,14 @@ index 028e55a4ec53e..e90c380444325 100644
+ u32 max_rx_size;
+ u32 max_tx_size;
+ u32 legacy_touch_cfg;
- };
-
- int ithc_reset(struct ithc *ithc);
--void ithc_set_active(struct ithc *ithc, unsigned int duration_us);
--int ithc_debug_init(struct ithc *ithc);
--void ithc_log_regs(struct ithc *ithc);
-
---
-2.45.1
-
-From b4563a0da733d5759de36d9e555ce81324dca286 Mon Sep 17 00:00:00 2001
-From: Hans de Goede <hdegoede@redhat.com>
-Date: Thu, 9 May 2024 16:15:49 +0200
-Subject: [PATCH] serial: Clear UPF_DEAD before calling
- tty_port_register_device_attr_serdev()
-
-If a serdev_device_driver is already loaded for a serdev_tty_port when it
-gets registered by tty_port_register_device_attr_serdev() then that
-driver's probe() method will be called immediately.
-
-The serdev_device_driver's probe() method should then be able to call
-serdev_device_open() successfully, but because UPF_DEAD is still dead
-serdev_device_open() will fail with -ENXIO in this scenario:
-
- serdev_device_open()
- ctrl->ops->open() /* this callback being ttyport_open() */
- tty->ops->open() /* this callback being uart_open() */
- tty_port_open()
- port->ops->activate() /* this callback being uart_port_activate() */
- Find bit UPF_DEAD is set in uport->flags and fail with errno -ENXIO.
-
-Fix this be clearing UPF_DEAD before tty_port_register_device_attr_serdev()
-note this only moves up the UPD_DEAD clearing a small bit, before:
-
- tty_port_register_device_attr_serdev();
- mutex_unlock(&tty_port.mutex);
- uart_port.flags &= ~UPF_DEAD;
- mutex_unlock(&port_mutex);
-
-after:
-
- uart_port.flags &= ~UPF_DEAD;
- tty_port_register_device_attr_serdev();
- mutex_unlock(&tty_port.mutex);
- mutex_unlock(&port_mutex);
-
-Reported-by: Weifeng Liu <weifeng.liu.z@gmail.com>
-Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@gmail.com/
-Tested-by: Weifeng Liu <weifeng.liu.z@gmail.com>
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-Link: https://lore.kernel.org/r/20240509141549.63704-1-hdegoede@redhat.com
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Patchset: surface-sam
----
- drivers/tty/serial/serial_core.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
-index c476d884356db..b47a277978a0b 100644
---- a/drivers/tty/serial/serial_core.c
-+++ b/drivers/tty/serial/serial_core.c
-@@ -3211,6 +3211,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
- if (uport->attr_group)
- uport->tty_groups[1] = uport->attr_group;
-
-+ /* Ensure serdev drivers can call serdev_device_open() right away */
-+ uport->flags &= ~UPF_DEAD;
++};
++
++int ithc_reset(struct ithc *ithc);
+
- /*
- * Register the port whether it's detected or not. This allows
- * setserial to be used to alter this port's parameters.
-@@ -3221,6 +3224,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
- if (!IS_ERR(tty_dev)) {
- device_set_wakeup_capable(tty_dev, 1);
- } else {
-+ uport->flags |= UPF_DEAD;
- dev_err(uport->dev, "Cannot register tty device on line %d\n",
- uport->line);
- }
-@@ -3426,8 +3430,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
- if (ret)
- goto err_unregister_port_dev;
-
-- port->flags &= ~UPF_DEAD;
--
- mutex_unlock(&port_mutex);
-
- return 0;
---
-2.45.1
-
-From 0864ded554efe90dd9603b61e82c604481ee5125 Mon Sep 17 00:00:00 2001
-From: Weifeng Liu <weifeng.liu.z@gmail.com>
-Date: Sun, 5 May 2024 21:07:50 +0800
-Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM
- probing
-
-Emits messages upon errors during probing of SAM. Hopefully this could
-provide useful context to user for the purpose of diagnosis when
-something miserable happen.
-
-Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com>
-Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
-Signed-off-by: Weifeng Liu <weifeng.liu.z@gmail.com>
-Link: https://lore.kernel.org/r/20240505130800.2546640-3-weifeng.liu.z@gmail.com
-Reviewed-by: Hans de Goede <hdegoede@redhat.com>
-Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-Patchset: surface-sam
----
- drivers/platform/surface/aggregator/core.c | 42 ++++++++++++++--------
- 1 file changed, 28 insertions(+), 14 deletions(-)
-
-diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
-index ba550eaa06fcf..797d0645bd77f 100644
---- a/drivers/platform/surface/aggregator/core.c
-+++ b/drivers/platform/surface/aggregator/core.c
-@@ -618,15 +618,17 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = {
-
- static int ssam_serial_hub_probe(struct serdev_device *serdev)
- {
-- struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev);
-+ struct device *dev = &serdev->dev;
-+ struct acpi_device *ssh = ACPI_COMPANION(dev);
- struct ssam_controller *ctrl;
- acpi_status astatus;
- int status;
-
-- if (gpiod_count(&serdev->dev, NULL) < 0)
-- return -ENODEV;
-+ status = gpiod_count(dev, NULL);
-+ if (status < 0)
-+ return dev_err_probe(dev, status, "no GPIO found\n");
-
-- status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios);
-+ status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
- if (status)
- return status;
-
-@@ -637,8 +639,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
-
- /* Initialize controller. */
- status = ssam_controller_init(ctrl, serdev);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "failed to initialize ssam controller\n");
- goto err_ctrl_init;
-+ }
-
- ssam_controller_lock(ctrl);
-
-@@ -646,12 +650,14 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
- serdev_device_set_drvdata(serdev, ctrl);
- serdev_device_set_client_ops(serdev, &ssam_serdev_ops);
- status = serdev_device_open(serdev);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "failed to open serdev device\n");
- goto err_devopen;
-+ }
-
- astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
- if (ACPI_FAILURE(astatus)) {
-- status = -ENXIO;
-+ status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n");
- goto err_devinit;
- }
-
-@@ -667,25 +673,33 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
- * states.
- */
- status = ssam_log_firmware_version(ctrl);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "failed to get firmware version\n");
- goto err_initrq;
-+ }
-
- status = ssam_ctrl_notif_d0_entry(ctrl);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "D0-entry notification failed\n");
- goto err_initrq;
-+ }
-
- status = ssam_ctrl_notif_display_on(ctrl);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "display-on notification failed\n");
- goto err_initrq;
-+ }
-
-- status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group);
-+ status = sysfs_create_group(&dev->kobj, &ssam_sam_group);
- if (status)
- goto err_initrq;
-
- /* Set up IRQ. */
- status = ssam_irq_setup(ctrl);
-- if (status)
-+ if (status) {
-+ dev_err_probe(dev, status, "failed to setup IRQ\n");
- goto err_irq;
-+ }
-
- /* Finally, set main controller reference. */
- status = ssam_try_set_controller(ctrl);
-@@ -702,7 +716,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
- * resumed. In short, this causes some spurious unwanted wake-ups.
- * For now let's thus default power/wakeup to false.
- */
-- device_set_wakeup_capable(&serdev->dev, true);
-+ device_set_wakeup_capable(dev, true);
- acpi_dev_clear_dependencies(ssh);
-
- return 0;
-@@ -710,7 +724,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
- err_mainref:
- ssam_irq_free(ctrl);
- err_irq:
-- sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group);
-+ sysfs_remove_group(&dev->kobj, &ssam_sam_group);
- err_initrq:
- ssam_controller_lock(ctrl);
- ssam_controller_shutdown(ctrl);
--
-2.45.1
+2.45.2
-From d44985653441ba783a830bd5efde2fcf3a3ea271 Mon Sep 17 00:00:00 2001
+From 5180e4810b868e0d3da85577b776a929cecf1d65 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Fri, 19 Apr 2024 20:41:47 +0200
Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is
@@ -8544,7 +6707,7 @@ Patchset: surface-sam
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
-index 7fc602e01487d..7e89f547999b2 100644
+index 7fc602e01487..7e89f547999b 100644
--- a/drivers/platform/surface/aggregator/controller.c
+++ b/drivers/platform/surface/aggregator/controller.c
@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl)
@@ -8558,9 +6721,9 @@ index 7fc602e01487d..7e89f547999b2 100644
/*
* Note: New events could still have been received after the previous
--
-2.45.1
+2.45.2
-From 6b6f860bbef0ba3f10f8dc151ac4e27d0a34c223 Mon Sep 17 00:00:00 2001
+From 144dbc865c07df0290009d509b31635aac53a907 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 22 Oct 2023 14:57:11 +0200
Subject: [PATCH] platform/surface: aggregator_registry: Add support for
@@ -8577,10 +6740,10 @@ Patchset: surface-sam
1 file changed, 3 insertions(+)
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 035d6b4105cd6..74688a2ed4b2e 100644
+index 1c4d74db08c9..f826489dc69d 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -374,6 +374,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
+@@ -395,6 +395,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop Go 2 */
{ "MSHW0290", (unsigned long)ssam_node_group_slg1 },
@@ -8591,9 +6754,9 @@ index 035d6b4105cd6..74688a2ed4b2e 100644
{ "MSHW0123", (unsigned long)ssam_node_group_sls },
--
-2.45.1
+2.45.2
-From 31b312c25822404e52a81de2525da5c7bae12864 Mon Sep 17 00:00:00 2001
+From 7b906ae84a56322a5098c77a774f5fb00b4318a5 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Mon, 20 Nov 2023 19:47:00 +0100
Subject: [PATCH] platform/surface: aggregator_registry: Add support for
@@ -8611,10 +6774,10 @@ Patchset: surface-sam
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 74688a2ed4b2e..f02a933160ff2 100644
+index f826489dc69d..ef59a7b66667 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -253,8 +253,8 @@ static const struct software_node *ssam_node_group_sl5[] = {
+@@ -273,8 +273,8 @@ static const struct software_node *ssam_node_group_sl5[] = {
NULL,
};
@@ -8625,7 +6788,7 @@ index 74688a2ed4b2e..f02a933160ff2 100644
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
-@@ -269,6 +269,20 @@ static const struct software_node *ssam_node_group_sls[] = {
+@@ -289,6 +289,20 @@ static const struct software_node *ssam_node_group_sls[] = {
NULL,
};
@@ -8646,7 +6809,7 @@ index 74688a2ed4b2e..f02a933160ff2 100644
/* Devices for Surface Laptop Go. */
static const struct software_node *ssam_node_group_slg1[] = {
&ssam_node_root,
-@@ -377,8 +391,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
+@@ -398,8 +412,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop Go 3 */
{ "MSHW0440", (unsigned long)ssam_node_group_slg1 },
@@ -8661,9 +6824,9 @@ index 74688a2ed4b2e..f02a933160ff2 100644
{ },
};
--
-2.45.1
+2.45.2
-From 42f6d14bda5e69c2b5a8d27cfcbd063a5922f876 Mon Sep 17 00:00:00 2001
+From d602c3714f0cc654b90de7800f844d6201eaa66b Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sun, 9 Jun 2024 20:05:57 +0200
Subject: [PATCH] platform/surface: aggregator_registry: Add support for
@@ -8681,10 +6844,10 @@ Patchset: surface-sam
1 file changed, 19 insertions(+)
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index f02a933160ff2..34df1bdad83bd 100644
+index ef59a7b66667..70a2ea5a1957 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -253,6 +253,22 @@ static const struct software_node *ssam_node_group_sl5[] = {
+@@ -273,6 +273,22 @@ static const struct software_node *ssam_node_group_sl5[] = {
NULL,
};
@@ -8707,7 +6870,7 @@ index f02a933160ff2..34df1bdad83bd 100644
/* Devices for Surface Laptop Studio 1. */
static const struct software_node *ssam_node_group_sls1[] = {
&ssam_node_root,
-@@ -382,6 +398,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
+@@ -403,6 +419,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
/* Surface Laptop 5 */
{ "MSHW0350", (unsigned long)ssam_node_group_sl5 },
@@ -8718,9 +6881,9 @@ index f02a933160ff2..34df1bdad83bd 100644
{ "MSHW0118", (unsigned long)ssam_node_group_slg1 },
--
-2.45.1
+2.45.2
-From 88fda328aea3bb7077cd39f854148276dcffcea3 Mon Sep 17 00:00:00 2001
+From 4bde7be038c7dced1b596c7d41e6f0bb3043d301 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 30 Dec 2023 18:07:54 +0100
Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator
@@ -8742,10 +6905,10 @@ Patchset: surface-sam
create mode 100644 drivers/hwmon/surface_temp.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
-index 83945397b6eb1..338ef73c96a3a 100644
+index e14ae18a973b..76eabe3e4435 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
-@@ -2070,6 +2070,16 @@ config SENSORS_SURFACE_FAN
+@@ -2093,6 +2093,16 @@ config SENSORS_SURFACE_FAN
Select M or Y here, if you want to be able to read the fan's speed.
@@ -8763,10 +6926,10 @@ index 83945397b6eb1..338ef73c96a3a 100644
tristate "Texas Instruments ADC128D818"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
-index 5c31808f6378d..de8bc99719e63 100644
+index e3f25475d1f0..eff74ab7f720 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
-@@ -208,6 +208,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+@@ -209,6 +209,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
@@ -8776,7 +6939,7 @@ index 5c31808f6378d..de8bc99719e63 100644
obj-$(CONFIG_SENSORS_TC74) += tc74.o
diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c
new file mode 100644
-index 0000000000000..48c3e826713f6
+index 000000000000..48c3e826713f
--- /dev/null
+++ b/drivers/hwmon/surface_temp.c
@@ -0,0 +1,165 @@
@@ -8946,9 +7109,9 @@ index 0000000000000..48c3e826713f6
+MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module");
+MODULE_LICENSE("GPL");
--
-2.45.1
+2.45.2
-From 17f0ec6ef1bc95e152af3a9f2b05ea669c75d24a Mon Sep 17 00:00:00 2001
+From ae82a35c632785771ebe2ad7f48006a1eb8f6a91 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
Date: Sat, 30 Dec 2023 18:12:23 +0100
Subject: [PATCH] hwmon: surface_temp: Add support for sensor names
@@ -8966,7 +7129,7 @@ Patchset: surface-sam
1 file changed, 96 insertions(+), 17 deletions(-)
diff --git a/drivers/hwmon/surface_temp.c b/drivers/hwmon/surface_temp.c
-index 48c3e826713f6..4c08926139dbf 100644
+index 48c3e826713f..4c08926139db 100644
--- a/drivers/hwmon/surface_temp.c
+++ b/drivers/hwmon/surface_temp.c
@@ -17,6 +17,27 @@
@@ -9141,379 +7304,121 @@ index 48c3e826713f6..4c08926139dbf 100644
"surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info,
NULL);
--
-2.45.1
+2.45.2
-From 54bfa02fe865b9f22d79b112a5244ce81e4961f1 Mon Sep 17 00:00:00 2001
+From 6a80e0b93ce1d8cf9d1b7e383b4b951fb4908294 Mon Sep 17 00:00:00 2001
From: Maximilian Luz <luzmaximilian@gmail.com>
-Date: Sat, 30 Dec 2023 18:21:12 +0100
-Subject: [PATCH] platform/surface: aggregator_registry: Add support for
- thermal sensors on the Surface Pro 9
+Date: Mon, 10 Jun 2024 21:47:47 +0200
+Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal
+ sensor support for Surface Laptop 5
-The Surface Pro 9 has thermal sensors connected via the Surface
-Aggregator Module. Add a device node to support those.
-
-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Patchset: surface-sam
---
- drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++
- 1 file changed, 7 insertions(+)
+ drivers/platform/surface/surface_aggregator_registry.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index 34df1bdad83bd..c0bf0cadcd258 100644
+index 70a2ea5a1957..6b568804f70b 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = {
- .parent = &ssam_node_root,
- };
-
-+/* Thermal sensors. */
-+static const struct software_node ssam_node_tmp_sensors = {
-+ .name = "ssam:01:03:01:00:02",
-+ .parent = &ssam_node_root,
-+};
-+
- /* Fan speed function. */
- static const struct software_node ssam_node_fan_speed = {
- .name = "ssam:01:05:01:01:01",
-@@ -341,6 +347,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
+@@ -265,7 +265,9 @@ static const struct software_node *ssam_node_group_sl5[] = {
+ &ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
+- &ssam_node_tmp_perf_profile,
++ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_tmp_sensors,
- &ssam_node_fan_speed,
- &ssam_node_pos_tablet_switch,
- &ssam_node_hid_kip_keyboard,
++ &ssam_node_fan_speed,
+ &ssam_node_hid_main_keyboard,
+ &ssam_node_hid_main_touchpad,
+ &ssam_node_hid_main_iid5,
--
-2.45.1
+2.45.2
-From 06c4b5ac6b6357227e45c53643729140d794b48d Mon Sep 17 00:00:00 2001
-From: Ivor Wanders <ivor@iwanders.net>
-Date: Sat, 16 Dec 2023 15:56:39 -0500
-Subject: [PATCH] platform/surface: platform_profile: add fan profile switching
-
-Change naming from tmp to platform profile to clarify the module may
-interact with both the TMP and FAN subystems. Add functionality that
-switches the fan profile when the platform profile is changed.
+From 3175ecd829a778ffef35956d8785877bb76fe4b0 Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Mon, 10 Jun 2024 21:48:02 +0200
+Subject: [PATCH] platform/surface: aggregator_registry: Add fan and thermal
+ sensor support for Surface Laptop Studio 2
-Signed-off-by: Ivor Wanders <ivor@iwanders.net>
Patchset: surface-sam
---
- .../surface/surface_aggregator_registry.c | 38 +++++---
- .../surface/surface_platform_profile.c | 86 ++++++++++++++++---
- 2 files changed, 100 insertions(+), 24 deletions(-)
+ drivers/platform/surface/surface_aggregator_registry.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
-index c0bf0cadcd258..07a4c4e1120d3 100644
+index 6b568804f70b..9046df95c043 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
-@@ -68,8 +68,8 @@ static const struct software_node ssam_node_bat_sb3base = {
- .parent = &ssam_node_hub_base,
- };
-
--/* Platform profile / performance-mode device. */
--static const struct software_node ssam_node_tmp_pprof = {
-+/* Platform profile / performance-mode device without a fan. */
-+static const struct software_node ssam_node_tmp_perf_profile = {
- .name = "ssam:01:03:01:00:01",
- .parent = &ssam_node_root,
- };
-@@ -86,6 +86,20 @@ static const struct software_node ssam_node_fan_speed = {
- .parent = &ssam_node_root,
- };
-
-+/* Platform profile / performance-mode device with a fan, such that
-+ * the fan controller profile can also be switched.
-+ */
-+static const struct property_entry ssam_node_tmp_perf_profile_has_fan[] = {
-+ PROPERTY_ENTRY_BOOL("has_fan"),
-+ { }
-+};
-+
-+static const struct software_node ssam_node_tmp_perf_profile_with_fan = {
-+ .name = "ssam:01:03:01:00:01",
-+ .parent = &ssam_node_root,
-+ .properties = ssam_node_tmp_perf_profile_has_fan,
-+};
-+
- /* Tablet-mode switch via KIP subsystem. */
- static const struct software_node ssam_node_kip_tablet_switch = {
- .name = "ssam:01:0e:01:00:01",
-@@ -214,7 +228,7 @@ static const struct software_node ssam_node_pos_tablet_switch = {
- */
- static const struct software_node *ssam_node_group_gen5[] = {
- &ssam_node_root,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- NULL,
- };
-
-@@ -225,7 +239,7 @@ static const struct software_node *ssam_node_group_sb3[] = {
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
- &ssam_node_bat_sb3base,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- &ssam_node_bas_dtx,
- &ssam_node_hid_base_keyboard,
- &ssam_node_hid_base_touchpad,
-@@ -239,7 +253,7 @@ static const struct software_node *ssam_node_group_sl3[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- &ssam_node_hid_main_keyboard,
- &ssam_node_hid_main_touchpad,
- &ssam_node_hid_main_iid5,
-@@ -251,7 +265,7 @@ static const struct software_node *ssam_node_group_sl5[] = {
+@@ -312,7 +312,9 @@ static const struct software_node *ssam_node_group_sls2[] = {
&ssam_node_root,
&ssam_node_bat_ac,
&ssam_node_bat_main,
- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- &ssam_node_hid_main_keyboard,
- &ssam_node_hid_main_touchpad,
- &ssam_node_hid_main_iid5,
-@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls1[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- &ssam_node_pos_tablet_switch,
- &ssam_node_hid_sam_keyboard,
- &ssam_node_hid_sam_penstash,
-@@ -296,7 +310,7 @@ static const struct software_node *ssam_node_group_sls2[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
++ &ssam_node_tmp_perf_profile_with_fan,
++ &ssam_node_tmp_sensors,
++ &ssam_node_fan_speed,
&ssam_node_pos_tablet_switch,
&ssam_node_hid_sam_keyboard,
&ssam_node_hid_sam_penstash,
-@@ -310,7 +324,7 @@ static const struct software_node *ssam_node_group_slg1[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- NULL,
- };
-
-@@ -319,7 +333,7 @@ static const struct software_node *ssam_node_group_sp7[] = {
- &ssam_node_root,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
+--
+2.45.2
+
+From aeef49471d7ec17f243c685b85c0c870c99e9e3d Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Fri, 28 Jun 2024 22:31:37 +0200
+Subject: [PATCH] platform/surface: aggregator_registry: Add Support for
+ Surface Pro 10
+
+Patchset: surface-sam
+---
+ .../surface/surface_aggregator_registry.c | 22 +++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
+index 9046df95c043..058f4edd8b66 100644
+--- a/drivers/platform/surface/surface_aggregator_registry.c
++++ b/drivers/platform/surface/surface_aggregator_registry.c
+@@ -377,6 +377,25 @@ static const struct software_node *ssam_node_group_sp9[] = {
NULL,
};
-@@ -329,7 +343,7 @@ static const struct software_node *ssam_node_group_sp8[] = {
- &ssam_node_hub_kip,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
-+ &ssam_node_tmp_perf_profile,
- &ssam_node_kip_tablet_switch,
- &ssam_node_hid_kip_keyboard,
- &ssam_node_hid_kip_penstash,
-@@ -346,7 +360,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
- &ssam_node_hub_kip,
- &ssam_node_bat_ac,
- &ssam_node_bat_main,
-- &ssam_node_tmp_pprof,
++/* Devices for Surface Pro 10 */
++static const struct software_node *ssam_node_group_sp10[] = {
++ &ssam_node_root,
++ &ssam_node_hub_kip,
++ &ssam_node_bat_ac,
++ &ssam_node_bat_main,
+ &ssam_node_tmp_perf_profile_with_fan,
- &ssam_node_tmp_sensors,
- &ssam_node_fan_speed,
- &ssam_node_pos_tablet_switch,
-diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c
-index a5a3941b3f43a..e54d0a8f7daa5 100644
---- a/drivers/platform/surface/surface_platform_profile.c
-+++ b/drivers/platform/surface/surface_platform_profile.c
-@@ -1,7 +1,7 @@
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Surface Platform Profile / Performance Mode driver for Surface System
-- * Aggregator Module (thermal subsystem).
-+ * Aggregator Module (thermal and fan subsystem).
- *
- * Copyright (C) 2021-2022 Maximilian Luz <luzmaximilian@gmail.com>
- */
-@@ -14,6 +14,7 @@
-
- #include <linux/surface_aggregator/device.h>
-
-+// Enum for the platform performance profile sent to the TMP module.
- enum ssam_tmp_profile {
- SSAM_TMP_PROFILE_NORMAL = 1,
- SSAM_TMP_PROFILE_BATTERY_SAVER = 2,
-@@ -21,15 +22,26 @@ enum ssam_tmp_profile {
- SSAM_TMP_PROFILE_BEST_PERFORMANCE = 4,
- };
-
-+// Enum for the fan profile sent to the FAN module. This fan profile is
-+// only sent to the EC if the 'has_fan' property is set. The integers are
-+// not a typo, they differ from the performance profile indices.
-+enum ssam_fan_profile {
-+ SSAM_FAN_PROFILE_NORMAL = 2,
-+ SSAM_FAN_PROFILE_BATTERY_SAVER = 1,
-+ SSAM_FAN_PROFILE_BETTER_PERFORMANCE = 3,
-+ SSAM_FAN_PROFILE_BEST_PERFORMANCE = 4,
++ &ssam_node_tmp_sensors,
++ &ssam_node_fan_speed,
++ &ssam_node_pos_tablet_switch,
++ &ssam_node_hid_kip_keyboard,
++ &ssam_node_hid_kip_penstash,
++ &ssam_node_hid_kip_touchpad,
++ &ssam_node_hid_kip_fwupd,
++ &ssam_node_hid_sam_sensors,
++ &ssam_node_hid_sam_ucm_ucsi,
++ NULL,
+};
+
- struct ssam_tmp_profile_info {
- __le32 profile;
- __le16 unknown1;
- __le16 unknown2;
- } __packed;
-
--struct ssam_tmp_profile_device {
-+struct ssam_platform_profile_device {
- struct ssam_device *sdev;
- struct platform_profile_handler handler;
-+ bool has_fan;
- };
-
- SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_tmp_profile_get, struct ssam_tmp_profile_info, {
-@@ -42,6 +54,13 @@ SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_profile_set, __le32, {
- .command_id = 0x03,
- });
-
-+SSAM_DEFINE_SYNC_REQUEST_W(__ssam_fan_profile_set, char, {
-+ .target_category = SSAM_SSH_TC_FAN,
-+ .target_id = SSAM_SSH_TID_SAM,
-+ .command_id = 0x0e,
-+ .instance_id = 0x01,
-+});
-+
- static int ssam_tmp_profile_get(struct ssam_device *sdev, enum ssam_tmp_profile *p)
- {
- struct ssam_tmp_profile_info info;
-@@ -62,7 +81,14 @@ static int ssam_tmp_profile_set(struct ssam_device *sdev, enum ssam_tmp_profile
- return ssam_retry(__ssam_tmp_profile_set, sdev, &profile_le);
- }
-
--static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
-+static int ssam_fan_profile_set(struct ssam_device *sdev, enum ssam_fan_profile p)
-+{
-+ char profile = p;
-+
-+ return ssam_retry(__ssam_fan_profile_set, sdev->ctrl, &profile);
-+}
-+
-+static int convert_ssam_tmp_to_profile(struct ssam_device *sdev, enum ssam_tmp_profile p)
- {
- switch (p) {
- case SSAM_TMP_PROFILE_NORMAL:
-@@ -83,7 +109,8 @@ static int convert_ssam_to_profile(struct ssam_device *sdev, enum ssam_tmp_profi
- }
- }
-
--static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profile_option p)
-+
-+static int convert_profile_to_ssam_tmp(struct ssam_device *sdev, enum platform_profile_option p)
- {
- switch (p) {
- case PLATFORM_PROFILE_LOW_POWER:
-@@ -105,20 +132,42 @@ static int convert_profile_to_ssam(struct ssam_device *sdev, enum platform_profi
- }
- }
-
-+static int convert_profile_to_ssam_fan(struct ssam_device *sdev, enum platform_profile_option p)
-+{
-+ switch (p) {
-+ case PLATFORM_PROFILE_LOW_POWER:
-+ return SSAM_FAN_PROFILE_BATTERY_SAVER;
-+
-+ case PLATFORM_PROFILE_BALANCED:
-+ return SSAM_FAN_PROFILE_NORMAL;
-+
-+ case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
-+ return SSAM_FAN_PROFILE_BETTER_PERFORMANCE;
-+
-+ case PLATFORM_PROFILE_PERFORMANCE:
-+ return SSAM_FAN_PROFILE_BEST_PERFORMANCE;
-+
-+ default:
-+ /* This should have already been caught by platform_profile_store(). */
-+ WARN(true, "unsupported platform profile");
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
- static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
- enum platform_profile_option *profile)
- {
-- struct ssam_tmp_profile_device *tpd;
-+ struct ssam_platform_profile_device *tpd;
- enum ssam_tmp_profile tp;
- int status;
-
-- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
-+ tpd = container_of(pprof, struct ssam_platform_profile_device, handler);
-
- status = ssam_tmp_profile_get(tpd->sdev, &tp);
- if (status)
- return status;
-- status = convert_ssam_to_profile(tpd->sdev, tp);
-+ status = convert_ssam_tmp_to_profile(tpd->sdev, tp);
- if (status < 0)
- return status;
-
-@@ -129,21 +178,32 @@ static int ssam_platform_profile_get(struct platform_profile_handler *pprof,
- static int ssam_platform_profile_set(struct platform_profile_handler *pprof,
- enum platform_profile_option profile)
- {
-- struct ssam_tmp_profile_device *tpd;
-+ struct ssam_platform_profile_device *tpd;
- int tp;
-
-- tpd = container_of(pprof, struct ssam_tmp_profile_device, handler);
-+ tpd = container_of(pprof, struct ssam_platform_profile_device, handler);
-+
-+ tp = convert_profile_to_ssam_tmp(tpd->sdev, profile);
-+ if (tp < 0)
-+ return tp;
+ /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
-- tp = convert_profile_to_ssam(tpd->sdev, profile);
-+ tp = ssam_tmp_profile_set(tpd->sdev, tp);
- if (tp < 0)
- return tp;
+@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
+ /* Surface Pro 9 */
+ { "MSHW0343", (unsigned long)ssam_node_group_sp9 },
-- return ssam_tmp_profile_set(tpd->sdev, tp);
-+ if (tpd->has_fan) {
-+ tp = convert_profile_to_ssam_fan(tpd->sdev, profile);
-+ if (tp < 0)
-+ return tp;
-+ tp = ssam_fan_profile_set(tpd->sdev, tp);
-+ }
++ /* Surface Pro 10 */
++ { "MSHW0510", (unsigned long)ssam_node_group_sp10 },
+
-+ return tp;
- }
-
- static int surface_platform_profile_probe(struct ssam_device *sdev)
- {
-- struct ssam_tmp_profile_device *tpd;
-+ struct ssam_platform_profile_device *tpd;
-
- tpd = devm_kzalloc(&sdev->dev, sizeof(*tpd), GFP_KERNEL);
- if (!tpd)
-@@ -154,6 +214,8 @@ static int surface_platform_profile_probe(struct ssam_device *sdev)
- tpd->handler.profile_get = ssam_platform_profile_get;
- tpd->handler.profile_set = ssam_platform_profile_set;
+ /* Surface Book 2 */
+ { "MSHW0107", (unsigned long)ssam_node_group_gen5 },
-+ tpd->has_fan = device_property_read_bool(&sdev->dev, "has_fan");
-+
- set_bit(PLATFORM_PROFILE_LOW_POWER, tpd->handler.choices);
- set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices);
- set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices);
--
-2.45.1
+2.45.2
-From bf55987e82f9ae913b51a6a269fc1a397930f049 Mon Sep 17 00:00:00 2001
+From 56def3328ab5c84c33a87c062448f1f97e545282 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
@@ -9570,10 +7475,10 @@ Patchset: surface-sam-over-hid
1 file changed, 35 insertions(+)
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
-index d6037a3286690..a290ebc77aea2 100644
+index 14ae0cfc325e..a3a9f81fb47f 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
-@@ -628,6 +628,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
+@@ -639,6 +639,28 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
return (ret == 1) ? 0 : -EIO;
}
@@ -9602,7 +7507,7 @@ index d6037a3286690..a290ebc77aea2 100644
static acpi_status
i2c_acpi_space_handler(u32 function, acpi_physical_address command,
u32 bits, u64 *value64,
-@@ -729,6 +751,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
+@@ -740,6 +762,19 @@ i2c_acpi_space_handler(u32 function, acpi_physical_address command,
}
break;
@@ -9623,9 +7528,9 @@ index d6037a3286690..a290ebc77aea2 100644
dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
accessor_type, client->addr);
--
-2.45.1
+2.45.2
-From ebfda7ad73dd90971be10e9d6f59c51c781accbb Mon Sep 17 00:00:00 2001
+From 99ca5a4092ea27b42c256940694e13a8f2abd457 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
@@ -9648,7 +7553,7 @@ Patchset: surface-sam-over-hid
create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c
diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig
-index b629e82af97c0..68656e8f309ed 100644
+index b629e82af97c..68656e8f309e 100644
--- a/drivers/platform/surface/Kconfig
+++ b/drivers/platform/surface/Kconfig
@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH
@@ -9666,7 +7571,7 @@ index b629e82af97c0..68656e8f309ed 100644
tristate "Surface DTX (Detachment System) Driver"
depends on SURFACE_AGGREGATOR
diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile
-index 53344330939bf..7efcd0cdb5329 100644
+index 53344330939b..7efcd0cdb532 100644
--- a/drivers/platform/surface/Makefile
+++ b/drivers/platform/surface/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o
@@ -9679,7 +7584,7 @@ index 53344330939bf..7efcd0cdb5329 100644
obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o
diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c
new file mode 100644
-index 0000000000000..8b816ed8f35c6
+index 000000000000..8b816ed8f35c
--- /dev/null
+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c
@@ -0,0 +1,162 @@
@@ -9846,9 +7751,9 @@ index 0000000000000..8b816ed8f35c6
+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1");
+MODULE_LICENSE("GPL");
--
-2.45.1
+2.45.2
-From 1e315f586b0b2bc375b96bb538a3be4c0b09d1ea Mon Sep 17 00:00:00 2001
+From 1afbbb29ce7bd15bbf4f812cbc034514bb667b43 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
@@ -9870,7 +7775,7 @@ Patchset: surface-button
1 file changed, 8 insertions(+), 25 deletions(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
-index f6d060377d189..b8603f74eb286 100644
+index f6d060377d18..b8603f74eb28 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -540,8 +540,8 @@ static const struct soc_device_data soc_device_MSHW0028 = {
@@ -9923,9 +7828,9 @@ index f6d060377d189..b8603f74eb286 100644
/*
--
-2.45.1
+2.45.2
-From ac551644781bce2145c901b16779114b273c4d49 Mon Sep 17 00:00:00 2001
+From 888fc8298e984f1cb23ac66e91a02d2e7f174919 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
@@ -9946,7 +7851,7 @@ Patchset: surface-button
1 file changed, 6 insertions(+), 24 deletions(-)
diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c
-index 2755601f979cd..4240c98ca2265 100644
+index 2755601f979c..4240c98ca226 100644
--- a/drivers/platform/surface/surfacepro3_button.c
+++ b/drivers/platform/surface/surfacepro3_button.c
@@ -149,7 +149,8 @@ static int surface_button_resume(struct device *dev)
@@ -9995,9 +7900,582 @@ index 2755601f979cd..4240c98ca2265 100644
--
-2.45.1
+2.45.2
+
+From 201768f64dd2128028bed46940ecd9ea85483973 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
+ Type-Cover
+
+The touchpad on the Type-Cover of the Surface Go 3 is sometimes not
+being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this
+issue.
+
+More specifically, the device in question is a fairly standard modern
+touchpad with pointer and touchpad input modes. During setup, the device
+needs to be switched from pointer- to touchpad-mode (which is done in
+hid-multitouch) to fully utilize it as intended. Unfortunately, however,
+this seems to occasionally fail silently, leaving the device in
+pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this.
+
+Link: https://github.com/linux-surface/linux-surface/issues/1059
+Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
+Patchset: surface-typecover
+---
+ drivers/usb/core/quirks.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
+index 13171454f959..a83beefd25f3 100644
+--- a/drivers/usb/core/quirks.c
++++ b/drivers/usb/core/quirks.c
+@@ -223,6 +223,9 @@ static const struct usb_device_id usb_quirk_list[] = {
+ /* Microsoft Surface Dock Ethernet (RTL8153 GigE) */
+ { USB_DEVICE(0x045e, 0x07c6), .driver_info = USB_QUIRK_NO_LPM },
+
++ /* Microsoft Surface Go 3 Type-Cover */
++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT },
++
+ /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */
+ { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME },
+
+--
+2.45.2
+
+From 9ae353f19e719e680d93710ec61aef6edefab6f1 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
+ suspending
+
+The Type Cover for Microsoft Surface devices supports a special usb
+control request to disable or enable the built-in keyboard backlight.
+On Windows, this request happens when putting the device into suspend or
+resuming it, without it the backlight of the Type Cover will remain
+enabled for some time even though the computer is suspended, which looks
+weird to the user.
+
+So add support for this special usb control request to hid-multitouch,
+which is the driver that's handling the Type Cover.
+
+The reason we have to use a pm_notifier for this instead of the usual
+suspend/resume methods is that those won't get called in case the usb
+device is already autosuspended.
+
+Also, if the device is autosuspended, we have to briefly autoresume it
+in order to send the request. Doing that should be fine, the usb-core
+driver does something similar during suspend inside choose_wakeup().
+
+To make sure we don't send that request to every device but only to
+devices which support it, add a new quirk
+MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk
+is only enabled for the usb id of the Surface Pro 2017 Type Cover, which
+is where I confirmed that it's working.
+
+Patchset: surface-typecover
+---
+ drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++-
+ 1 file changed, 98 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index 56fc78841f24..a266449065a0 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -34,7 +34,10 @@
+ #include <linux/device.h>
+ #include <linux/hid.h>
+ #include <linux/module.h>
++#include <linux/pm_runtime.h>
+ #include <linux/slab.h>
++#include <linux/suspend.h>
++#include <linux/usb.h>
+ #include <linux/input/mt.h>
+ #include <linux/jiffies.h>
+ #include <linux/string.h>
+@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels");
+ MODULE_LICENSE("GPL");
+
+ #include "hid-ids.h"
++#include "usbhid/usbhid.h"
+
+ /* quirks to control the device */
+ #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0)
+@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL");
+ #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
+ #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
+ #define MT_QUIRK_ORIENTATION_INVERT BIT(22)
++#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23)
+
+ #define MT_INPUTMODE_TOUCHSCREEN 0x02
+ #define MT_INPUTMODE_TOUCHPAD 0x03
+
+ #define MT_BUTTONTYPE_CLICKPAD 0
+
++#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
++
+ enum latency_mode {
+ HID_LATENCY_NORMAL = 0,
+ HID_LATENCY_HIGH = 1,
+@@ -168,6 +175,8 @@ struct mt_device {
+
+ struct list_head applications;
+ struct list_head reports;
++
++ struct notifier_block pm_notifier;
+ };
+
+ static void mt_post_parse_default_settings(struct mt_device *td,
+@@ -212,6 +221,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
+ #define MT_CLS_GOOGLE 0x0111
+ #define MT_CLS_RAZER_BLADE_STEALTH 0x0112
+ #define MT_CLS_SMART_TECH 0x0113
++#define MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER 0x0114
+
+ #define MT_DEFAULT_MAXCONTACT 10
+ #define MT_MAX_MAXCONTACT 250
+@@ -396,6 +406,16 @@ static const struct mt_class mt_classes[] = {
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_SEPARATE_APP_REPORT,
+ },
++ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
++ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
++ MT_QUIRK_ALWAYS_VALID |
++ MT_QUIRK_IGNORE_DUPLICATES |
++ MT_QUIRK_HOVERING |
++ MT_QUIRK_CONTACT_CNT_ACCURATE |
++ MT_QUIRK_STICKY_FINGERS |
++ MT_QUIRK_WIN8_PTP_BUTTONS,
++ .export_all_inputs = true
++ },
+ { }
+ };
+
+@@ -1720,6 +1740,69 @@ static void mt_expired_timeout(struct timer_list *t)
+ clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
+ }
+
++static void get_type_cover_backlight_field(struct hid_device *hdev,
++ struct hid_field **field)
++{
++ struct hid_report_enum *rep_enum;
++ struct hid_report *rep;
++ struct hid_field *cur_field;
++ int i, j;
++
++ rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
++ list_for_each_entry(rep, &rep_enum->report_list, list) {
++ for (i = 0; i < rep->maxfield; i++) {
++ cur_field = rep->field[i];
++
++ for (j = 0; j < cur_field->maxusage; j++) {
++ if (cur_field->usage[j].hid
++ == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
++ *field = cur_field;
++ return;
++ }
++ }
++ }
++ }
++}
++
++static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
++{
++ struct usb_device *udev = hid_to_usb_dev(hdev);
++ struct hid_field *field = NULL;
++
++ /* Wake up the device in case it's already suspended */
++ pm_runtime_get_sync(&udev->dev);
++
++ get_type_cover_backlight_field(hdev, &field);
++ if (!field) {
++ hid_err(hdev, "couldn't find backlight field\n");
++ goto out;
++ }
++
++ field->value[field->index] = enabled ? 0x01ff00ff : 0x00ff00ff;
++ hid_hw_request(hdev, field->report, HID_REQ_SET_REPORT);
++
++out:
++ pm_runtime_put_sync(&udev->dev);
++}
++
++static int mt_pm_notifier(struct notifier_block *notifier,
++ unsigned long pm_event,
++ void *unused)
++{
++ struct mt_device *td =
++ container_of(notifier, struct mt_device, pm_notifier);
++ struct hid_device *hdev = td->hdev;
++
++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT) {
++ if (pm_event == PM_SUSPEND_PREPARE)
++ update_keyboard_backlight(hdev, 0);
++ else if (pm_event == PM_POST_SUSPEND)
++ update_keyboard_backlight(hdev, 1);
++ }
++
++ return NOTIFY_DONE;
++}
++
+ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ {
+ int ret, i;
+@@ -1743,6 +1826,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
+ hid_set_drvdata(hdev, td);
+
++ td->pm_notifier.notifier_call = mt_pm_notifier;
++ register_pm_notifier(&td->pm_notifier);
++
+ INIT_LIST_HEAD(&td->applications);
+ INIT_LIST_HEAD(&td->reports);
+
+@@ -1781,15 +1867,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ timer_setup(&td->release_timer, mt_expired_timeout, 0);
+
+ ret = hid_parse(hdev);
+- if (ret != 0)
++ if (ret != 0) {
++ unregister_pm_notifier(&td->pm_notifier);
+ return ret;
++ }
+
+ if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID)
+ mt_fix_const_fields(hdev, HID_DG_CONTACTID);
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+- if (ret)
++ if (ret) {
++ unregister_pm_notifier(&td->pm_notifier);
+ return ret;
++ }
+
+ ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
+ if (ret)
+@@ -1839,6 +1929,7 @@ static void mt_remove(struct hid_device *hdev)
+ {
+ struct mt_device *td = hid_get_drvdata(hdev);
+
++ unregister_pm_notifier(&td->pm_notifier);
+ del_timer_sync(&td->release_timer);
+
+ sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
+@@ -2235,6 +2326,11 @@ static const struct hid_device_id mt_devices[] = {
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ USB_DEVICE_ID_XIROKU_CSR2) },
+
++ /* Microsoft Surface type cover */
++ { .driver_data = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
++ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
++ USB_VENDOR_ID_MICROSOFT, 0x09c0) },
++
+ /* Google MT devices */
+ { .driver_data = MT_CLS_GOOGLE,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE,
+--
+2.45.2
+
+From 922102cc310758a2655f9bb3eb9a413bc551b1a7 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
+ switch
+
+The Surface Pro Type Cover has several non standard HID usages in it's
+hid report descriptor.
+I noticed that, upon folding the typecover back, a vendor specific range
+of 4 32 bit integer hid usages is transmitted.
+Only the first byte of the message seems to convey reliable information
+about the keyboard state.
+
+0x22 => Normal (keys enabled)
+0x33 => Folded back (keys disabled)
+0x53 => Rotated left/right side up (keys disabled)
+0x13 => Cover closed (keys disabled)
+0x43 => Folded back and Tablet upside down (keys disabled)
+This list may not be exhaustive.
+
+The tablet mode switch will be disabled for a value of 0x22 and enabled
+on any other value.
+
+Patchset: surface-typecover
+---
+ drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------
+ 1 file changed, 122 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
+index a266449065a0..060c706e936a 100644
+--- a/drivers/hid/hid-multitouch.c
++++ b/drivers/hid/hid-multitouch.c
+@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");
+ #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
+ #define MT_QUIRK_ORIENTATION_INVERT BIT(22)
+ #define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23)
++#define MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24)
+
+ #define MT_INPUTMODE_TOUCHSCREEN 0x02
+ #define MT_INPUTMODE_TOUCHPAD 0x03
+@@ -84,6 +85,8 @@ MODULE_LICENSE("GPL");
+ #define MT_BUTTONTYPE_CLICKPAD 0
+
+ #define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086
++#define MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE 0xff050072
++#define MS_TYPE_COVER_APPLICATION 0xff050050
+
+ enum latency_mode {
+ HID_LATENCY_NORMAL = 0,
+@@ -408,6 +411,7 @@ static const struct mt_class mt_classes[] = {
+ },
+ { .name = MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER,
+ .quirks = MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT |
++ MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH |
+ MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_HOVERING |
+@@ -1389,6 +1393,9 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ field->application != HID_CP_CONSUMER_CONTROL &&
+ field->application != HID_GD_WIRELESS_RADIO_CTLS &&
+ field->application != HID_GD_SYSTEM_MULTIAXIS &&
++ !(field->application == MS_TYPE_COVER_APPLICATION &&
++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) &&
+ !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
+ application->quirks & MT_QUIRK_ASUS_CUSTOM_UP))
+ return -1;
+@@ -1416,6 +1423,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ return 1;
+ }
+
++ /*
++ * The Microsoft Surface Pro Typecover has a non-standard HID
++ * tablet mode switch on a vendor specific usage page with vendor
++ * specific usage.
++ */
++ if (field->application == MS_TYPE_COVER_APPLICATION &&
++ application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
++ usage->type = EV_SW;
++ usage->code = SW_TABLET_MODE;
++ *max = SW_MAX;
++ *bit = hi->input->swbit;
++ return 1;
++ }
++
+ if (rdata->is_mt_collection)
+ return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
+ application);
+@@ -1437,6 +1459,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ {
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_report_data *rdata;
++ struct input_dev *input;
+
+ rdata = mt_find_report_data(td, field->report);
+ if (rdata && rdata->is_mt_collection) {
+@@ -1444,6 +1467,19 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ return -1;
+ }
+
++ /*
++ * We own an input device which acts as a tablet mode switch for
++ * the Surface Pro Typecover.
++ */
++ if (field->application == MS_TYPE_COVER_APPLICATION &&
++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
++ input = hi->input;
++ input_set_capability(input, EV_SW, SW_TABLET_MODE);
++ input_report_switch(input, SW_TABLET_MODE, 0);
++ return -1;
++ }
++
+ /* let hid-core decide for the others */
+ return 0;
+ }
+@@ -1453,11 +1489,21 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
+ {
+ struct mt_device *td = hid_get_drvdata(hid);
+ struct mt_report_data *rdata;
++ struct input_dev *input;
+
+ rdata = mt_find_report_data(td, field->report);
+ if (rdata && rdata->is_mt_collection)
+ return mt_touch_event(hid, field, usage, value);
+
++ if (field->application == MS_TYPE_COVER_APPLICATION &&
++ rdata->application->quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH &&
++ usage->hid == MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE) {
++ input = field->hidinput->input;
++ input_report_switch(input, SW_TABLET_MODE, (value & 0xFF) != 0x22);
++ input_sync(input);
++ return 1;
++ }
++
+ return 0;
+ }
+
+@@ -1610,6 +1656,42 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
+ app->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
+ }
+
++static int get_type_cover_field(struct hid_report_enum *rep_enum,
++ struct hid_field **field, int usage)
++{
++ struct hid_report *rep;
++ struct hid_field *cur_field;
++ int i, j;
++
++ list_for_each_entry(rep, &rep_enum->report_list, list) {
++ for (i = 0; i < rep->maxfield; i++) {
++ cur_field = rep->field[i];
++ if (cur_field->application != MS_TYPE_COVER_APPLICATION)
++ continue;
++ for (j = 0; j < cur_field->maxusage; j++) {
++ if (cur_field->usage[j].hid == usage) {
++ *field = cur_field;
++ return true;
++ }
++ }
++ }
++ }
++ return false;
++}
++
++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev)
++{
++ struct hid_field *field;
++
++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
++ &field,
++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
++ hid_hw_request(hdev, field->report, HID_REQ_GET_REPORT);
++ } else {
++ hid_err(hdev, "couldn't find tablet mode field\n");
++ }
++}
++
+ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ {
+ struct mt_device *td = hid_get_drvdata(hdev);
+@@ -1658,6 +1740,13 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
+ /* force BTN_STYLUS to allow tablet matching in udev */
+ __set_bit(BTN_STYLUS, hi->input->keybit);
+ break;
++ case MS_TYPE_COVER_APPLICATION:
++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
++ suffix = "Tablet Mode Switch";
++ request_type_cover_tablet_mode_switch(hdev);
++ break;
++ }
++ fallthrough;
+ default:
+ suffix = "UNKNOWN";
+ break;
+@@ -1740,30 +1829,6 @@ static void mt_expired_timeout(struct timer_list *t)
+ clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
+ }
+
+-static void get_type_cover_backlight_field(struct hid_device *hdev,
+- struct hid_field **field)
+-{
+- struct hid_report_enum *rep_enum;
+- struct hid_report *rep;
+- struct hid_field *cur_field;
+- int i, j;
+-
+- rep_enum = &hdev->report_enum[HID_FEATURE_REPORT];
+- list_for_each_entry(rep, &rep_enum->report_list, list) {
+- for (i = 0; i < rep->maxfield; i++) {
+- cur_field = rep->field[i];
+-
+- for (j = 0; j < cur_field->maxusage; j++) {
+- if (cur_field->usage[j].hid
+- == MS_TYPE_COVER_FEATURE_REPORT_USAGE) {
+- *field = cur_field;
+- return;
+- }
+- }
+- }
+- }
+-}
+-
+ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
+ {
+ struct usb_device *udev = hid_to_usb_dev(hdev);
+@@ -1772,8 +1837,9 @@ static void update_keyboard_backlight(struct hid_device *hdev, bool enabled)
+ /* Wake up the device in case it's already suspended */
+ pm_runtime_get_sync(&udev->dev);
+
+- get_type_cover_backlight_field(hdev, &field);
+- if (!field) {
++ if (!get_type_cover_field(&hdev->report_enum[HID_FEATURE_REPORT],
++ &field,
++ MS_TYPE_COVER_FEATURE_REPORT_USAGE)) {
+ hid_err(hdev, "couldn't find backlight field\n");
+ goto out;
+ }
+@@ -1907,13 +1973,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state)
+
+ static int mt_reset_resume(struct hid_device *hdev)
+ {
++ struct mt_device *td = hid_get_drvdata(hdev);
++
+ mt_release_contacts(hdev);
+ mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
++
++ /* Request an update on the typecover folding state on resume
++ * after reset.
++ */
++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
++ request_type_cover_tablet_mode_switch(hdev);
++
+ return 0;
+ }
+
+ static int mt_resume(struct hid_device *hdev)
+ {
++ struct mt_device *td = hid_get_drvdata(hdev);
++
+ /* Some Elan legacy devices require SET_IDLE to be set on resume.
+ * It should be safe to send it to other devices too.
+ * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
+@@ -1922,12 +1999,31 @@ static int mt_resume(struct hid_device *hdev)
+
+ mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true);
+
++ /* Request an update on the typecover folding state on resume. */
++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH)
++ request_type_cover_tablet_mode_switch(hdev);
++
+ return 0;
+ }
+
+ static void mt_remove(struct hid_device *hdev)
+ {
+ struct mt_device *td = hid_get_drvdata(hdev);
++ struct hid_field *field;
++ struct input_dev *input;
++
++ /* Reset tablet mode switch on disconnect. */
++ if (td->mtclass.quirks & MT_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH) {
++ if (get_type_cover_field(&hdev->report_enum[HID_INPUT_REPORT],
++ &field,
++ MS_TYPE_COVER_TABLET_MODE_SWITCH_USAGE)) {
++ input = field->hidinput->input;
++ input_report_switch(input, SW_TABLET_MODE, 0);
++ input_sync(input);
++ } else {
++ hid_err(hdev, "couldn't find tablet mode field\n");
++ }
++ }
+
+ unregister_pm_notifier(&td->pm_notifier);
+ del_timer_sync(&td->release_timer);
+--
+2.45.2
-From 9e0b83c9668c3d0e8e5ce9c254697056940a205d Mon Sep 17 00:00:00 2001
+From dc75889e49675c868d33320a996c33d183fee94a 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
@@ -10022,7 +8500,7 @@ Patchset: surface-shutdown
3 files changed, 40 insertions(+)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
-index af2996d0d17ff..3ce0fb61257dc 100644
+index af2996d0d17f..3ce0fb61257d 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev)
@@ -10036,13 +8514,13 @@ index af2996d0d17ff..3ce0fb61257dc 100644
if (drv && drv->shutdown)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
-index eff7f5df08e27..d1cb4ff3ebc57 100644
+index 568410e64ce6..f59d8fb36335 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
-@@ -6253,3 +6253,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev)
- pdev->d3cold_delay = 1000;
- }
- DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec);
+@@ -6273,3 +6273,39 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev)
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout);
+ #endif
+
+static const struct dmi_system_id no_shutdown_dmi_table[] = {
+ /*
@@ -10080,7 +8558,7 @@ index eff7f5df08e27..d1cb4ff3ebc57 100644
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x466d, quirk_no_shutdown); // Thunderbolt 4 NHI
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x46a8, quirk_no_shutdown); // GPU
diff --git a/include/linux/pci.h b/include/linux/pci.h
-index 16493426a04ff..0eb821624056d 100644
+index cafc5ab1cbcb..64bb5aca2c13 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -465,6 +465,7 @@ struct pci_dev {
@@ -10092,9 +8570,9 @@ index 16493426a04ff..0eb821624056d 100644
atomic_t enable_cnt; /* pci_enable_device has been called */
--
-2.45.1
+2.45.2
-From 739ab84095d8ea8ec8fe05447706c6eb2ffa3f35 Mon Sep 17 00:00:00 2001
+From 41732ed4458eb3b08b4a658f1cd617d83c90cec6 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
@@ -10108,7 +8586,7 @@ Patchset: surface-gpe
1 file changed, 17 insertions(+)
diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c
-index 62fd4004db31a..103fc4468262a 100644
+index 62fd4004db31..103fc4468262 100644
--- a/drivers/platform/surface/surface_gpe.c
+++ b/drivers/platform/surface/surface_gpe.c
@@ -41,6 +41,11 @@ static const struct property_entry lid_device_props_l4F[] = {
@@ -10143,9 +8621,9 @@ index 62fd4004db31a..103fc4468262a 100644
.ident = "Surface Book 1",
.matches = {
--
-2.45.1
+2.45.2
-From 44ed44fe421e484bcf2de223d7e8077302635772 Mon Sep 17 00:00:00 2001
+From 2d145df171e42d90ac54b0bdc42e77337e99679a 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
@@ -10205,10 +8683,10 @@ Patchset: cameras
1 file changed, 3 insertions(+)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
-index d1464324de951..5d865a34dd9db 100644
+index 503773707e01..a292a20c4315 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
-@@ -2181,6 +2181,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
+@@ -2176,6 +2176,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used,
static void acpi_default_enumeration(struct acpi_device *device)
{
@@ -10219,9 +8697,9 @@ index d1464324de951..5d865a34dd9db 100644
* Do not enumerate devices with enumeration_by_parent flag set as
* they will be enumerated by their respective parents.
--
-2.45.1
+2.45.2
-From d9d5afcea9880a957d6a8d975a122b4f54ec28c2 Mon Sep 17 00:00:00 2001
+From f0e749b5b8f19dca95eaf7b24c925f7684669993 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
@@ -10247,10 +8725,10 @@ Patchset: cameras
1 file changed, 30 insertions(+)
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
-index 61bc54299a591..a61af0f4e9fce 100644
+index 8d95579436a9..cbfb59ed5985 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
-@@ -44,6 +44,13 @@
+@@ -45,6 +45,13 @@
((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \
)
@@ -10264,7 +8742,7 @@ index 61bc54299a591..a61af0f4e9fce 100644
#define IOAPIC_RANGE_START (0xfee00000)
#define IOAPIC_RANGE_END (0xfeefffff)
#define IOVA_START_ADDR (0x1000)
-@@ -227,12 +234,14 @@ int intel_iommu_enabled = 0;
+@@ -223,12 +230,14 @@ int intel_iommu_enabled = 0;
EXPORT_SYMBOL_GPL(intel_iommu_enabled);
static int dmar_map_ipts = 1;
@@ -10279,7 +8757,7 @@ index 61bc54299a591..a61af0f4e9fce 100644
#define IDENTMAP_IPTS 16
const struct iommu_ops intel_iommu_ops;
-@@ -2409,6 +2418,9 @@ static int device_def_domain_type(struct device *dev)
+@@ -2203,6 +2212,9 @@ static int device_def_domain_type(struct device *dev)
if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
return IOMMU_DOMAIN_IDENTITY;
@@ -10289,7 +8767,7 @@ index 61bc54299a591..a61af0f4e9fce 100644
if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev))
return IOMMU_DOMAIN_IDENTITY;
}
-@@ -2711,6 +2723,9 @@ static int __init init_dmars(void)
+@@ -2505,6 +2517,9 @@ static int __init init_dmars(void)
iommu_set_root_entry(iommu);
}
@@ -10299,7 +8777,7 @@ index 61bc54299a591..a61af0f4e9fce 100644
if (!dmar_map_ipts)
iommu_identity_mapping |= IDENTMAP_IPTS;
-@@ -4884,6 +4899,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
+@@ -4630,6 +4645,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev)
disable_igfx_iommu = 1;
}
@@ -10318,7 +8796,7 @@ index 61bc54299a591..a61af0f4e9fce 100644
static void quirk_iommu_ipts(struct pci_dev *dev)
{
if (!IS_IPTS(dev))
-@@ -4931,6 +4958,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
+@@ -4677,6 +4704,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163A, quirk_iommu_igfx);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x163D, quirk_iommu_igfx);
@@ -10329,9 +8807,9 @@ index 61bc54299a591..a61af0f4e9fce 100644
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x34E4, quirk_iommu_ipts);
--
-2.45.1
+2.45.2
-From bbf2fb14fae6c6bda12e156ff9d027913ab7860f Mon Sep 17 00:00:00 2001
+From 197059f84ca0575efb65a4667023e9e14c53fe87 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
@@ -10348,7 +8826,7 @@ Patchset: cameras
1 file changed, 7 insertions(+)
diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c
-index 1e107fd49f828..e3e1696e7f0ee 100644
+index 1e107fd49f82..e3e1696e7f0e 100644
--- a/drivers/platform/x86/intel/int3472/tps68470.c
+++ b/drivers/platform/x86/intel/int3472/tps68470.c
@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
@@ -10366,9 +8844,9 @@ index 1e107fd49f828..e3e1696e7f0ee 100644
return 0;
--
-2.45.1
+2.45.2
-From bc2732708fc2a71f7fe3808aa84cc6eabbdd1285 Mon Sep 17 00:00:00 2001
+From cff4d571011727ee47c29f21c9b1d255ca4efe8e 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
@@ -10390,7 +8868,7 @@ Patchset: cameras
1 file changed, 14 insertions(+)
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
-index 07b302e093407..1d3097bc7e487 100644
+index 07b302e09340..1d3097bc7e48 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -83,12 +83,26 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
@@ -10421,9 +8899,9 @@ index 07b302e093407..1d3097bc7e487 100644
agpio, func, polarity);
if (ret)
--
-2.45.1
+2.45.2
-From 0180b848e145642574d2a91175f92050dcec1ec7 Mon Sep 17 00:00:00 2001
+From 31cab2b99a833eab39602f61e3f3f801884f8980 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
@@ -10438,7 +8916,7 @@ Patchset: cameras
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
-index 30f61e04ecaf5..9c1292ca85522 100644
+index 30f61e04ecaf..9c1292ca8552 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1051,7 +1051,7 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -10460,9 +8938,9 @@ index 30f61e04ecaf5..9c1292ca85522 100644
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(ov7251_test_pattern_menu) - 1,
--
-2.45.1
+2.45.2
-From 67553f37af4ea73f824108a08666b537c68972e5 Mon Sep 17 00:00:00 2001
+From b17d182f347660c7c2e873d0a2e21b57ce44858c 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
@@ -10481,10 +8959,10 @@ Patchset: cameras
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
-index 3ec323bd528b1..b55570a0142cb 100644
+index c477723c07bf..83413048eb35 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
-@@ -796,6 +796,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
+@@ -795,6 +795,10 @@ int __v4l2_async_register_subdev(struct v4l2_subdev *sd, struct module *module)
INIT_LIST_HEAD(&sd->asc_list);
@@ -10496,7 +8974,7 @@ index 3ec323bd528b1..b55570a0142cb 100644
* No reference taken. The reference is held by the device (struct
* v4l2_subdev.dev), and async sub-device does not exist independently
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
-index 89c7192148dfb..44eca113e7727 100644
+index 89c7192148df..44eca113e772 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -1219,10 +1219,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
@@ -10511,9 +8989,9 @@ index 89c7192148dfb..44eca113e7727 100644
if (ret < 0)
goto out_cleanup;
--
-2.45.1
+2.45.2
-From 82dff76b0fc0e6d8fec20339edcb52fcb3eb1fac Mon Sep 17 00:00:00 2001
+From c51c33aa1cdbea15c1b493b300f66408d8306bd9 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
@@ -10529,7 +9007,7 @@ Patchset: cameras
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c
-index e3e1696e7f0ee..423dc555093f7 100644
+index e3e1696e7f0e..423dc555093f 100644
--- a/drivers/platform/x86/intel/int3472/tps68470.c
+++ b/drivers/platform/x86/intel/int3472/tps68470.c
@@ -17,7 +17,7 @@
@@ -10552,9 +9030,9 @@ index e3e1696e7f0ee..423dc555093f7 100644
for (i = 0; i < board_data->n_gpiod_lookups; i++)
gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]);
--
-2.45.1
+2.45.2
-From ac5b449b3e7da53dfff6ab59dc32d9714eb2f106 Mon Sep 17 00:00:00 2001
+From b37b24f5e18fd586452ec4a7cc978c3360074e42 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
@@ -10572,7 +9050,7 @@ Patchset: cameras
1 file changed, 5 insertions(+)
diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h
-index 7807fa329db00..2d2abb25b944f 100644
+index 7807fa329db0..2d2abb25b944 100644
--- a/include/linux/mfd/tps68470.h
+++ b/include/linux/mfd/tps68470.h
@@ -34,6 +34,7 @@
@@ -10593,9 +9071,9 @@ index 7807fa329db00..2d2abb25b944f 100644
+
#endif /* __LINUX_MFD_TPS68470_H */
--
-2.45.1
+2.45.2
-From 3bdaa0c3e0b7dfa3b441e7d19d3f08ff3708e354 Mon Sep 17 00:00:00 2001
+From 8ef5b1010e49d11964f2dd7da3c3271f5f9bf503 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
@@ -10618,7 +9096,7 @@ Patchset: cameras
create mode 100644 drivers/leds/leds-tps68470.c
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
-index 05e6af88b88cd..c120eb0b5aa8e 100644
+index 05e6af88b88c..c120eb0b5aa8 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -909,6 +909,18 @@ config LEDS_TPS6105X
@@ -10641,7 +9119,7 @@ index 05e6af88b88cd..c120eb0b5aa8e 100644
tristate "LED support for SGI Octane machines"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
-index effdfc6f1e951..6ce609b2cdac6 100644
+index effdfc6f1e95..6ce609b2cdac 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
@@ -10654,7 +9132,7 @@ index effdfc6f1e951..6ce609b2cdac6 100644
obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c
new file mode 100644
-index 0000000000000..35aeb5db89c8f
+index 000000000000..35aeb5db89c8
--- /dev/null
+++ b/drivers/leds/leds-tps68470.c
@@ -0,0 +1,185 @@
@@ -10844,9 +9322,9 @@ index 0000000000000..35aeb5db89c8f
+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC");
+MODULE_LICENSE("GPL v2");
--
-2.45.1
+2.45.2
-From 05501de0dab9bc531918dcf2b8aa7e679760fd7b Mon Sep 17 00:00:00 2001
+From ca688e057ec8149ccd01d2c7876b707aa33bdbc8 Mon Sep 17 00:00:00 2001
From: mojyack <mojyack@gmail.com>
Date: Sat, 3 Feb 2024 12:59:53 +0900
Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on
@@ -10860,7 +9338,7 @@ Patchset: cameras
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
-index 3df58eb3e8822..81aff2d5d8988 100644
+index 3df58eb3e882..81aff2d5d898 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -538,18 +538,18 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq)
@@ -10891,9 +9369,9 @@ index 3df58eb3e8822..81aff2d5d8988 100644
r = imgu_s_stream(imgu, false);
if (!r)
--
-2.45.1
+2.45.2
-From c85328d7df3de31a574e42f66192c6a944f48bde Mon Sep 17 00:00:00 2001
+From d267b727836905eaefc1541eb743479338827db5 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
@@ -10909,7 +9387,7 @@ Patchset: cameras
1 file changed, 3 insertions(+)
diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c
-index c626ed845928c..0094cfda57ea8 100644
+index c626ed845928..0094cfda57ea 100644
--- a/drivers/media/i2c/dw9719.c
+++ b/drivers/media/i2c/dw9719.c
@@ -82,6 +82,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719)
@@ -10923,9 +9401,9 @@ index c626ed845928c..0094cfda57ea8 100644
cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret);
--
-2.45.1
+2.45.2
-From e0b584d3054d7c69d2e1b4f2ca54e42b79ee5446 Mon Sep 17 00:00:00 2001
+From 68bfb06084548d1f7d23fc2c5e7c4b70262078b3 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
@@ -10948,7 +9426,7 @@ Patchset: amd-gpio
1 file changed, 17 insertions(+)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
-index 4bf82dbd2a6b5..7a8cb090c6568 100644
+index 4bf82dbd2a6b..7a8cb090c656 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -22,6 +22,7 @@
@@ -10990,9 +9468,9 @@ index 4bf82dbd2a6b5..7a8cb090c6568 100644
mp_config_acpi_legacy_irqs();
--
-2.45.1
+2.45.2
-From dafa7b45eecb1e02dc857158566d2fb3087fa71f Mon Sep 17 00:00:00 2001
+From f72f4d6bc2d6e1f1ec68422cffaed5e77820c6c5 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
@@ -11007,7 +9485,7 @@ Patchset: amd-gpio
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
-index 7a8cb090c6568..0faafc323e673 100644
+index 7a8cb090c656..0faafc323e67 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void)
@@ -11032,9 +9510,9 @@ index 7a8cb090c6568..0faafc323e673 100644
};
--
-2.45.1
+2.45.2
-From e3e62473f885786f1b57421f5fed86ac5ba402ac Mon Sep 17 00:00:00 2001
+From ca8843e551ab3528c958bc8efaa51356dbdc23de 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
@@ -11057,7 +9535,7 @@ Patchset: rtc
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
-index 1d670dbe4d1dd..71c9e375ca1ca 100644
+index 1d670dbe4d1d..71c9e375ca1c 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -432,6 +432,14 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr,
@@ -11142,5 +9620,5 @@ index 1d670dbe4d1dd..71c9e375ca1ca 100644
ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
if (ret)
--
-2.45.1
+2.45.2