From ee7306c6937f331f0fc0882a29a947c0a9560b3e Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Fri, 9 Aug 2024 19:26:14 +0200 Subject: kernel 6.10.3 --- SOURCES/linux-surface.patch | 5532 ++++++++++++++++--------------------------- 1 file changed, 2005 insertions(+), 3527 deletions(-) (limited to 'SOURCES/linux-surface.patch') 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 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 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?= 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 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?= 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 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 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 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 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 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 -Date: Mon, 15 Apr 2024 10:22:55 +0200 -Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile - with -Wmissing-prototypes. - -Signed-off-by: Dorian Stoll -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 +2.45.2 -From 4b17942da35790b0e703a87267545f5a9f08e1cf Mon Sep 17 00:00:00 2001 +From 52e90ab224f06fd648ca85cd43a91670a9a4e683 Mon Sep 17 00:00:00 2001 From: Dorian Stoll 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 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 +Signed-off-by: Maximilian Stoll 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,153 +4571,18 @@ 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); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); + -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c new file mode 100644 -index 0000000000000..87ed4aa70fda0 +index 000000000000..065646ab499e --- /dev/null -+++ b/drivers/hid/ithc/ithc-main.c -@@ -0,0 +1,728 @@ ++++ b/drivers/hid/ithc/ithc-hid.c +@@ -0,0 +1,207 @@ +// 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; } @@ -4814,14 +4591,18 @@ index 0000000000000..87ed4aa70fda0 +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); ++ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; ++ 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))) ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); ++ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), ++ msecs_to_jiffies(200))) { ++ ithc_log_regs(ithc); + return 0; ++ } + if (retries > 5) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "failed to read report descriptor\n"); + return -ETIMEDOUT; + } @@ -4835,32 +4616,38 @@ index 0000000000000..87ed4aa70fda0 + struct ithc *ithc = hdev->driver_data; + if (!buf || !len) + return -EINVAL; -+ u32 code; ++ ++ struct ithc_data d = { .size = len, .data = buf }; ++ buf[0] = reportnum; ++ + if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ code = DMA_TX_CODE_OUTPUT_REPORT; -+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ code = DMA_TX_CODE_SET_FEATURE; -+ } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ code = DMA_TX_CODE_GET_FEATURE; -+ } else { -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; ++ d.type = ITHC_DATA_OUTPUT_REPORT; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; + } -+ buf[0] = reportnum; + -+ if (reqtype == HID_REQ_GET_REPORT) { ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { ++ d.type = ITHC_DATA_SET_FEATURE; ++ CHECK_RET(ithc_dma_tx, ithc, &d); ++ return 0; ++ } ++ ++ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { ++ d.type = ITHC_DATA_GET_FEATURE; ++ d.data = &reportnum; ++ d.size = 1; ++ + // Prepare for response. -+ mutex_lock(&ithc->hid_get_feature_mutex); -+ ithc->hid_get_feature_buf = buf; -+ ithc->hid_get_feature_size = len; -+ mutex_unlock(&ithc->hid_get_feature_mutex); ++ 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); ++ int r = CHECK(ithc_dma_tx, ithc, &d); + if (!r) { -+ r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, -+ !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); ++ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, ++ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); + if (!r) + r = -ETIMEDOUT; + else if (r < 0) @@ -4871,17 +4658,86 @@ index 0000000000000..87ed4aa70fda0 + + // 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); ++ 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; ++ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", ++ rtype, reqtype, reportnum); ++ return -EINVAL; ++} ++ ++// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to ++// cast away the const to avoid a compiler warning... ++#define NOCONST(x) ((void *)x) ++ ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) ++{ ++ WARN_ON(!ithc->hid.dev); ++ if (!ithc->hid.dev) ++ return; ++ ++ switch (d->type) { ++ ++ case ITHC_DATA_IGNORE: ++ return; ++ ++ case ITHC_DATA_ERROR: ++ CHECK(ithc_reset, ithc); ++ return; ++ ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ // Response to the report descriptor request sent by ithc_hid_parse(). ++ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); ++ WRITE_ONCE(ithc->hid.parse_done, true); ++ wake_up(&ithc->hid.wait_parse); ++ return; ++ ++ case ITHC_DATA_INPUT_REPORT: ++ { ++ // Standard HID input report. ++ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); ++ if (r < 0) { ++ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", ++ r, d->size, d->size ? *(u8 *)d->data : 0); ++ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, ++ d->data, min(d->size, 0x400u), 0); ++ } ++ return; ++ } ++ ++ case ITHC_DATA_GET_FEATURE: ++ { ++ // Response to a 'get feature' request sent by ithc_hid_raw_request(). ++ bool done = false; ++ mutex_lock(&ithc->hid.get_feature_mutex); ++ if (ithc->hid.get_feature_buf) { ++ if (d->size < ithc->hid.get_feature_size) ++ ithc->hid.get_feature_size = d->size; ++ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); ++ ithc->hid.get_feature_buf = NULL; ++ done = true; ++ } ++ mutex_unlock(&ithc->hid.get_feature_mutex); ++ if (done) { ++ wake_up(&ithc->hid.wait_get_feature); ++ } else { ++ // Received data without a matching request, or the request already ++ // timed out. (XXX What's the correct thing to do here?) ++ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, ++ NOCONST(d->data), d->size, 1); ++ } ++ return; ++ } ++ ++ default: ++ pci_err(ithc->pci, "unhandled data type %i\n", d->type); ++ return; ++ } +} + +static struct hid_ll_driver ithc_ll_driver = { @@ -4900,7 +4756,7 @@ index 0000000000000..87ed4aa70fda0 + hid_destroy_device(*hidm); +} + -+static int ithc_hid_init(struct ithc *ithc) ++int ithc_hid_init(struct ithc *ithc) +{ + struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); + if (!hidm) @@ -4915,207 +4771,160 @@ index 0000000000000..87ed4aa70fda0 + 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->vendor = ithc->vendor_id; ++ hid->product = ithc->product_id; + hid->version = 0x100; + hid->dev.parent = &ithc->pci->dev; + hid->driver_data = ithc; + -+ ithc->hid = hid; ++ ithc->hid.dev = hid; ++ ++ init_waitqueue_head(&ithc->hid.wait_parse); ++ init_waitqueue_head(&ithc->hid.wait_get_feature); ++ mutex_init(&ithc->hid.get_feature_mutex); ++ + return 0; +} + -+// Interrupts/polling +diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h +new file mode 100644 +index 000000000000..599eb912c8c8 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-hid.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + -+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; -+} ++enum ithc_data_type { ++ ITHC_DATA_IGNORE, ++ ITHC_DATA_RAW, ++ ITHC_DATA_ERROR, ++ ITHC_DATA_REPORT_DESCRIPTOR, ++ ITHC_DATA_INPUT_REPORT, ++ ITHC_DATA_OUTPUT_REPORT, ++ ITHC_DATA_GET_FEATURE, ++ ITHC_DATA_SET_FEATURE, ++}; + -+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; -+} ++struct ithc_data { ++ enum ithc_data_type type; ++ u32 size; ++ const void *data; ++}; + -+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); -+} ++struct ithc_hid { ++ struct hid_device *dev; ++ bool parse_done; ++ wait_queue_head_t wait_parse; ++ wait_queue_head_t wait_get_feature; ++ struct mutex get_feature_mutex; ++ void *get_feature_buf; ++ size_t get_feature_size; ++}; + -+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); -+} ++int ithc_hid_init(struct ithc *ithc); ++void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); + -+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); -+} +diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c +new file mode 100644 +index 000000000000..8883987fb352 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.c +@@ -0,0 +1,254 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause + -+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); -+} ++#include "ithc.h" + -+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); -+} ++#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) ++#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) + -+static void ithc_process(struct ithc *ithc) -+{ -+ ithc_log_regs(ithc); ++#define DEVCFG_TOUCH_MASK 0x3f ++#define DEVCFG_TOUCH_ENABLE BIT(0) ++#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) ++#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) ++#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) ++#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) + -+ 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; ++#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" + -+ // 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); -+ } -+ } ++#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) ++#define DEVCFG_SPI_CLKDIV_8 BIT(4) ++#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) ++#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) ++#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) ++#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) ++#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) ++#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat ++#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) ++#define DEVCFG_SPI_UNKNOWN_25 BIT(25) ++#define DEVCFG_SPI_UNKNOWN_26 BIT(26) ++#define DEVCFG_SPI_UNKNOWN_27 BIT(27) ++#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this ++#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? + -+ // 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)); -+ } -+ } ++struct ithc_device_config { // (Example values are from an SP7+.) ++ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) ++ u32 error; // 04 = 0x00000000 ++ u32 dma_buf_sizes; // 08 = 0x000a00ff ++ u32 touch_cfg; // 0c = 0x0000001c ++ u32 touch_state; // 10 = 0x0000001c ++ u32 device_id; // 14 = 0x43495424 = "$TIC" ++ u32 spi_config; // 18 = 0xfda00a2e ++ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. ++ u16 product_id; // 1e = 0x0c1a ++ u32 revision; // 20 = 0x00000001 ++ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) ++ u32 command; // 28 = 0x00000000 ++ u32 fw_mode; // 2c = 0x00000000 (for fw update?) ++ u32 _unknown_30; // 30 = 0x00000000 ++ u8 eds_minor_ver; // 34 = 0x5e ++ u8 eds_major_ver; // 35 = 0x03 ++ u8 interface_rev; // 36 = 0x04 ++ u8 eu_kernel_ver; // 37 = 0x04 ++ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) ++ u32 _unknown_3c; // 3c = 0x00000002 ++}; ++static_assert(sizeof(struct ithc_device_config) == 64); + -+ // 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); -+ } ++#define RX_CODE_INPUT_REPORT 3 ++#define RX_CODE_FEATURE_REPORT 4 ++#define RX_CODE_REPORT_DESCRIPTOR 5 ++#define RX_CODE_RESET 7 + -+ // 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); -+ } ++#define TX_CODE_SET_FEATURE 3 ++#define TX_CODE_GET_FEATURE 4 ++#define TX_CODE_OUTPUT_REPORT 5 ++#define TX_CODE_GET_REPORT_DESCRIPTOR 7 + -+ ithc_log_regs(ithc); ++static int ithc_set_device_enabled(struct ithc *ithc, bool enable) ++{ ++ u32 x = ithc->legacy_touch_cfg = ++ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | ++ DEVCFG_TOUCH_HID_REPORT_ENABLE | ++ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); ++ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, ++ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); +} + -+static irqreturn_t ithc_interrupt_thread(int irq, void *arg) ++int ithc_legacy_init(struct ithc *ithc) +{ -+ 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); ++ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); + + // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); + -+ // 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; ++ // Setting this bit may be necessary on ADL devices. ++ switch (ithc->pci->device) { ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: ++ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: ++ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); ++ break; ++ } + + // Take the touch device out of reset. + bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); @@ -5123,36 +4932,45 @@ index 0000000000000..87ed4aa70fda0 + 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)) ++ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) + break; + if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); ++ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", ++ readl(&ithc->regs->irq_cause)); + return -ETIMEDOUT; + } -+ pci_warn(ithc->pci, "invalid state, retrying reset\n"); ++ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); + bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); + if (msleep_interruptible(1000)) + return -EINTR; + } + ithc_log_regs(ithc); + -+ // 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); ++ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); + + // Read configuration data. ++ u32 spi_cfg; + for (int retries = 0; ; retries++) { + ithc_log_regs(ithc); -+ 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; ++ struct ithc_device_config config = { 0 }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); ++ u32 *p = (void *)&config; + pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (ithc_is_config_valid(ithc)) ++ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { ++ spi_cfg = config.spi_config; ++ ithc->vendor_id = config.vendor_id; ++ ithc->product_id = config.product_id; ++ ithc->product_rev = config.revision; ++ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); ++ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); ++ ithc->legacy_touch_cfg = config.touch_cfg; ++ ithc->have_config = true; + break; ++ } + if (retries > 10) { + pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ ithc->config.device_id); ++ config.device_id); + return -EIO; + } + pci_warn(ithc->pci, "failed to read config, retrying\n"); @@ -5163,2057 +4981,566 @@ index 0000000000000..87ed4aa70fda0 + + // 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)); ++ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, ++ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : ++ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : ++ SPI_MODE_SINGLE, ++ SPI_MODE_SINGLE); + CHECK_RET(ithc_set_device_enabled, ithc, true); + ithc_log_regs(ithc); + return 0; +} + -+int ithc_reset(struct ithc *ithc) ++void ithc_legacy_exit(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; ++ CHECK(ithc_set_device_enabled, ithc, false); +} + -+static void ithc_stop(void *res) ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) +{ -+ struct ithc *ithc = res; -+ pci_dbg(ithc->pci, "stopping\n"); -+ ithc_log_regs(ithc); ++ const struct { ++ u32 code; ++ u32 data_size; ++ u32 _unknown[14]; ++ } *hdr = src; + -+ 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); ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // Note: RX data is not padded, even though TX data must be padded. ++ if (len != sizeof(*hdr) + hdr->data_size) ++ return -EMSGSIZE; + -+ // 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); ++ dest->data = hdr + 1; ++ dest->size = hdr->data_size; + -+ ithc_log_regs(ithc); -+ pci_dbg(ithc->pci, "stopped\n"); ++ switch (hdr->code) { ++ case RX_CODE_RESET: ++ // The THC sends a reset request when we need to reinitialize the device. ++ // This usually only happens if we send an invalid command or put the device ++ // in a bad state. ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case RX_CODE_REPORT_DESCRIPTOR: ++ // The descriptor is preceded by 8 nul bytes. ++ if (hdr->data_size < 8) ++ return -ENODATA; ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = (char *)(hdr + 1) + 8; ++ dest->size = hdr->data_size - 8; ++ return 0; ++ case RX_CODE_INPUT_REPORT: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ return 0; ++ case RX_CODE_FEATURE_REPORT: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ return 0; ++ default: ++ return -EINVAL; ++ } +} + -+static void ithc_clear_drvdata(void *res) ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) +{ -+ struct pci_dev *pci = res; -+ pci_set_drvdata(pci, NULL); -+} ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; + -+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"); ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: + return -EINVAL; + } -+ 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); ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; + -+ // 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]; ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); + -+ // 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; -+ } ++ return sizeof(*hdr) + padded; ++} + -+ // 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); +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 000000000000..28d692462072 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-legacy.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + -+ 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; ++int ithc_legacy_init(struct ithc *ithc); ++void ithc_legacy_exit(struct ithc *ithc); ++int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); + -+ // 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); +diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c +new file mode 100644 +index 000000000000..ac56c253674b +--- /dev/null ++++ b/drivers/hid/ithc/ithc-main.c +@@ -0,0 +1,431 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause + -+ CHECK_RET(ithc_hid_init, ithc); ++#include "ithc.h" + -+ // 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); -+ } ++MODULE_DESCRIPTION("Intel Touch Host Controller driver"); ++MODULE_LICENSE("Dual BSD/GPL"); + -+ if (ithc_use_rx0) -+ ithc_dma_rx_enable(ithc, 0); -+ if (ithc_use_rx1) -+ ithc_dma_rx_enable(ithc, 1); ++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); + -+ // 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); ++// Module parameters + -+ CHECK(ithc_debug_init, ithc); ++static bool ithc_use_polling = false; ++module_param_named(poll, ithc_use_polling, bool, 0); ++MODULE_PARM_DESC(poll, "Use polling instead of interrupts"); + -+ pci_dbg(pci, "started\n"); -+ return 0; -+} ++// 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 int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) -+{ -+ pci_dbg(pci, "device probe\n"); -+ return ithc_start(pci); -+} ++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 void ithc_remove(struct pci_dev *pci) -+{ -+ pci_dbg(pci, "device remove\n"); -+ // all cleanup is handled by devres -+} ++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)"); + -+// 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_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 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 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 int ithc_freeze(struct device *dev) ++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) +{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm freeze\n"); -+ devres_release_group(dev, ithc_start); -+ return 0; ++ 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 int ithc_thaw(struct device *dev) ++static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) +{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm thaw\n"); -+ return ithc_start(pci); ++ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, ++ &ithc->regs->dma_rx[channel].status); +} + -+static int ithc_restore(struct device *dev) ++static void ithc_clear_interrupts(struct ithc *ithc) +{ -+ struct pci_dev *pci = to_pci_dev(dev); -+ pci_dbg(pci, "pm restore\n"); -+ return ithc_start(pci); ++ 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 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) ++static void ithc_idle_timer_callback(struct timer_list *t) +{ -+ return pci_register_driver(&ithc_driver); ++ struct ithc *ithc = container_of(t, struct ithc, idle_timer); ++ ithc_set_ltr_idle(ithc); +} + -+static void __exit ithc_exit(void) ++static void ithc_process(struct ithc *ithc) +{ -+ pci_unregister_driver(&ithc_driver); -+} ++ ithc_log_regs(ithc); + -+module_init(ithc_init); -+module_exit(ithc_exit); ++ // 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)); + -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 ++ 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; + -+#include "ithc.h" ++ // 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"); ++ } + -+#define reg_num(r) (0x1fff & (u16)(__force u64)(r)) ++ // 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); ++ } + -+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); ++ ithc_log_regs(ithc); +} + -+void bitsb(__iomem u8 *reg, u8 mask, u8 val) ++static irqreturn_t ithc_interrupt_thread(int irq, void *arg) +{ -+ 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); ++ 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; +} + -+int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) ++static int ithc_poll_thread(void *arg) +{ -+ 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; ++ 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); + } -+ 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; -+} ++// Device initialization and shutdown + -+int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) ++static void ithc_disable(struct ithc *ithc) +{ -+ 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; ++ 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); +} + -+int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) ++static int ithc_init_device(struct ithc *ithc) +{ -+ 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; ++ // Read ACPI config for QuickSPI mode ++ struct ithc_acpi_config cfg = { 0 }; ++ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); ++ if (!cfg.has_config) ++ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); ++ else ++ ithc_print_acpi_config(ithc, &cfg); ++ ithc->use_quickspi = cfg.has_config; + -+ // 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); ++ // Shut down device ++ ithc_log_regs(ithc); ++ bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; ++ ithc_disable(ithc); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); ++ ithc_log_regs(ithc); + -+ // 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]); ++ // 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; + -+ // 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); ++ // Set Latency Tolerance Reporting config. The device will automatically ++ // apply these values depending on whether it is active or idle. ++ // If active value is too high, DMA buffer data can become truncated. ++ // By default, we set the active LTR value to 50us, and idle to 100ms. ++ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 ++ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 ++ : 50 * 1000; ++ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 ++ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 ++ : 100 * 1000 * 1000; ++ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); + -+ // 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]); ++ if (ithc->use_quickspi) ++ CHECK_RET(ithc_quickspi_init, ithc, &cfg); ++ else ++ CHECK_RET(ithc_legacy_init, ithc); + -+ 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) ++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; ++} + -+#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? ++static void ithc_stop(void *res) ++{ ++ struct ithc *ithc = res; ++ pci_dbg(ithc->pci, "stopping\n"); ++ ithc_log_regs(ithc); + -+#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 ++ if (ithc->poll_thread) ++ CHECK(kthread_stop, ithc->poll_thread); ++ if (ithc->irq >= 0) ++ disable_irq(ithc->irq); ++ if (ithc->use_quickspi) ++ ithc_quickspi_exit(ithc); ++ else ++ ithc_legacy_exit(ithc); ++ ithc_disable(ithc); ++ del_timer_sync(&ithc->idle_timer); + -+#define ERROR_STATUS_DMA BIT(28) -+#define ERROR_STATUS_SPI BIT(30) ++ // 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); + -+#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) ++ ithc_log_regs(ithc); ++ pci_dbg(ithc->pci, "stopped\n"); ++} + -+#define SPI_CMD_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define SPI_CMD_CONTROL_IRQ BIT(1) ++static void ithc_clear_drvdata(void *res) ++{ ++ struct pci_dev *pci = res; ++ pci_set_drvdata(pci, NULL); ++} + -+#define SPI_CMD_CODE_READ 4 -+#define SPI_CMD_CODE_WRITE 6 ++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; + -+#define SPI_CMD_STATUS_DONE BIT(0) -+#define SPI_CMD_STATUS_ERROR BIT(1) -+#define SPI_CMD_STATUS_BUSY BIT(3) ++ // 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); + -+#define DMA_TX_CONTROL_SEND BIT(0) // cleared by device when sending is complete -+#define DMA_TX_CONTROL_IRQ BIT(3) ++ // 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]; + -+#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? ++ // 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; ++ } + -+#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) ++ // Initialize THC and touch device. ++ CHECK_RET(ithc_init_device, ithc); + -+#define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? -+#define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices ++ // Initialize HID and DMA. ++ CHECK_RET(ithc_hid_init, ithc); ++ if (ithc_use_rx0) ++ CHECK_RET(ithc_dma_rx_init, ithc, 0); ++ if (ithc_use_rx1) ++ CHECK_RET(ithc_dma_rx_init, ithc, 1); ++ CHECK_RET(ithc_dma_tx_init, ithc); + -+#define DMA_RX_WRAP_FLAG BIT(7) ++ timer_setup(&ithc->idle_timer, ithc_idle_timer_callback, 0); + -+#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) ++ // 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); + -+// 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) ++ // 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); ++ } + -+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); ++ if (ithc_use_rx0) ++ ithc_dma_rx_enable(ithc, 0); ++ if (ithc_use_rx1) ++ ithc_dma_rx_enable(ithc, 1); + -+#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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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; ++ // 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); + -+ 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; ++ CHECK(ithc_debug_init_device, ithc); + -+ 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; -+}; ++ ithc_set_ltr_idle(ithc); + -+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); ++ pci_dbg(pci, "started\n"); ++ return 0; ++} + --- -2.45.1 - -From 2537922b2f0c1d0002a2afe6d0fc79695add8e60 Mon Sep 17 00:00:00 2001 -From: quo -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 -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; ++static int ithc_probe(struct pci_dev *pci, const struct pci_device_id *id) ++{ ++ pci_dbg(pci, "device probe\n"); ++ return ithc_start(pci); ++} + -+void __init ithc_debug_init_module(void) ++static void ithc_remove(struct pci_dev *pci) +{ -+ 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; ++ pci_dbg(pci, "device remove\n"); ++ // all cleanup is handled by devres +} + -+void __exit ithc_debug_exit_module(void) ++// 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) +{ -+ debugfs_remove_recursive(dbg_dir); -+ dbg_dir = NULL; ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm suspend\n"); ++ devres_release_group(dev, ithc_start); ++ return 0; +} + - 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 */ ++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); ++} + -+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); ++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; ++} + -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 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.c -@@ -0,0 +1,207 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+static int ithc_hid_start(struct hid_device *hdev) { return 0; } -+static void ithc_hid_stop(struct hid_device *hdev) { } -+static int ithc_hid_open(struct hid_device *hdev) { return 0; } -+static void ithc_hid_close(struct hid_device *hdev) { } -+ -+static int ithc_hid_parse(struct hid_device *hdev) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ const struct ithc_data get_report_desc = { .type = ITHC_DATA_REPORT_DESCRIPTOR }; -+ WRITE_ONCE(ithc->hid.parse_done, false); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ CHECK_RET(ithc_dma_tx, ithc, &get_report_desc); -+ if (wait_event_timeout(ithc->hid.wait_parse, READ_ONCE(ithc->hid.parse_done), -+ msecs_to_jiffies(200))) { -+ ithc_log_regs(ithc); -+ return 0; -+ } -+ if (retries > 5) { -+ ithc_log_regs(ithc); -+ pci_err(ithc->pci, "failed to read report descriptor\n"); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -+ } -+} -+ -+static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -+ size_t len, unsigned char rtype, int reqtype) -+{ -+ struct ithc *ithc = hdev->driver_data; -+ if (!buf || !len) -+ return -EINVAL; -+ -+ struct ithc_data d = { .size = len, .data = buf }; -+ buf[0] = reportnum; -+ -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_OUTPUT_REPORT; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -+ d.type = ITHC_DATA_SET_FEATURE; -+ CHECK_RET(ithc_dma_tx, ithc, &d); -+ return 0; -+ } -+ -+ if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -+ d.type = ITHC_DATA_GET_FEATURE; -+ d.data = &reportnum; -+ d.size = 1; -+ -+ // Prepare for response. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = buf; -+ ithc->hid.get_feature_size = len; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ -+ // Transmit 'get feature' request. -+ int r = CHECK(ithc_dma_tx, ithc, &d); -+ if (!r) { -+ r = wait_event_interruptible_timeout(ithc->hid.wait_get_feature, -+ !ithc->hid.get_feature_buf, msecs_to_jiffies(1000)); -+ if (!r) -+ r = -ETIMEDOUT; -+ else if (r < 0) -+ r = -EINTR; -+ else -+ r = 0; -+ } -+ -+ // If everything went ok, the buffer has been filled with the response data. -+ // Return the response size. -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ ithc->hid.get_feature_buf = NULL; -+ if (!r) -+ r = ithc->hid.get_feature_size; -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ return r; -+ } -+ -+ pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -+ rtype, reqtype, reportnum); -+ return -EINVAL; -+} -+ -+// FIXME hid_input_report()/hid_parse_report() currently don't take const buffers, so we have to -+// cast away the const to avoid a compiler warning... -+#define NOCONST(x) ((void *)x) -+ -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d) -+{ -+ WARN_ON(!ithc->hid.dev); -+ if (!ithc->hid.dev) -+ return; -+ -+ switch (d->type) { -+ -+ case ITHC_DATA_IGNORE: -+ return; -+ -+ case ITHC_DATA_ERROR: -+ CHECK(ithc_reset, ithc); -+ return; -+ -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ // Response to the report descriptor request sent by ithc_hid_parse(). -+ CHECK(hid_parse_report, ithc->hid.dev, NOCONST(d->data), d->size); -+ WRITE_ONCE(ithc->hid.parse_done, true); -+ wake_up(&ithc->hid.wait_parse); -+ return; -+ -+ case ITHC_DATA_INPUT_REPORT: -+ { -+ // Standard HID input report. -+ int r = hid_input_report(ithc->hid.dev, HID_INPUT_REPORT, NOCONST(d->data), d->size, 1); -+ if (r < 0) { -+ pci_warn(ithc->pci, "hid_input_report failed with %i (size %u, report ID 0x%02x)\n", -+ r, d->size, d->size ? *(u8 *)d->data : 0); -+ print_hex_dump_debug(DEVNAME " report: ", DUMP_PREFIX_OFFSET, 32, 1, -+ d->data, min(d->size, 0x400u), 0); -+ } -+ return; -+ } -+ -+ case ITHC_DATA_GET_FEATURE: -+ { -+ // Response to a 'get feature' request sent by ithc_hid_raw_request(). -+ bool done = false; -+ mutex_lock(&ithc->hid.get_feature_mutex); -+ if (ithc->hid.get_feature_buf) { -+ if (d->size < ithc->hid.get_feature_size) -+ ithc->hid.get_feature_size = d->size; -+ memcpy(ithc->hid.get_feature_buf, d->data, ithc->hid.get_feature_size); -+ ithc->hid.get_feature_buf = NULL; -+ done = true; -+ } -+ mutex_unlock(&ithc->hid.get_feature_mutex); -+ if (done) { -+ wake_up(&ithc->hid.wait_get_feature); -+ } else { -+ // Received data without a matching request, or the request already -+ // timed out. (XXX What's the correct thing to do here?) -+ CHECK(hid_input_report, ithc->hid.dev, HID_FEATURE_REPORT, -+ NOCONST(d->data), d->size, 1); -+ } -+ return; -+ } -+ -+ default: -+ pci_err(ithc->pci, "unhandled data type %i\n", d->type); -+ return; -+ } -+} -+ -+static struct hid_ll_driver ithc_ll_driver = { -+ .start = ithc_hid_start, -+ .stop = ithc_hid_stop, -+ .open = ithc_hid_open, -+ .close = ithc_hid_close, -+ .parse = ithc_hid_parse, -+ .raw_request = ithc_hid_raw_request, -+}; -+ -+static void ithc_hid_devres_release(struct device *dev, void *res) -+{ -+ struct hid_device **hidm = res; -+ if (*hidm) -+ hid_destroy_device(*hidm); -+} -+ -+int ithc_hid_init(struct ithc *ithc) -+{ -+ struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -+ if (!hidm) -+ return -ENOMEM; -+ devres_add(&ithc->pci->dev, hidm); -+ struct hid_device *hid = hid_allocate_device(); -+ if (IS_ERR(hid)) -+ return PTR_ERR(hid); -+ *hidm = hid; -+ -+ strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -+ strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -+ hid->ll_driver = &ithc_ll_driver; -+ hid->bus = BUS_PCI; -+ hid->vendor = ithc->vendor_id; -+ hid->product = ithc->product_id; -+ hid->version = 0x100; -+ hid->dev.parent = &ithc->pci->dev; -+ hid->driver_data = ithc; -+ -+ ithc->hid.dev = hid; -+ -+ init_waitqueue_head(&ithc->hid.wait_parse); -+ init_waitqueue_head(&ithc->hid.wait_get_feature); -+ mutex_init(&ithc->hid.get_feature_mutex); -+ -+ return 0; -+} -+ -diff --git a/drivers/hid/ithc/ithc-hid.h b/drivers/hid/ithc/ithc-hid.h -new file mode 100644 -index 0000000000000..599eb912c8c84 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-hid.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+enum ithc_data_type { -+ ITHC_DATA_IGNORE, -+ ITHC_DATA_RAW, -+ ITHC_DATA_ERROR, -+ ITHC_DATA_REPORT_DESCRIPTOR, -+ ITHC_DATA_INPUT_REPORT, -+ ITHC_DATA_OUTPUT_REPORT, -+ ITHC_DATA_GET_FEATURE, -+ ITHC_DATA_SET_FEATURE, -+}; -+ -+struct ithc_data { -+ enum ithc_data_type type; -+ u32 size; -+ const void *data; -+}; -+ -+struct ithc_hid { -+ struct hid_device *dev; -+ bool parse_done; -+ wait_queue_head_t wait_parse; -+ wait_queue_head_t wait_get_feature; -+ struct mutex get_feature_mutex; -+ void *get_feature_buf; -+ size_t get_feature_size; -+}; -+ -+int ithc_hid_init(struct ithc *ithc); -+void ithc_hid_process_data(struct ithc *ithc, struct ithc_data *d); -+ -diff --git a/drivers/hid/ithc/ithc-legacy.c b/drivers/hid/ithc/ithc-legacy.c -new file mode 100644 -index 0000000000000..5c1da11e3f1d2 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.c -@@ -0,0 +1,252 @@ -+// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -+ -+#include "ithc.h" -+ -+#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) -+#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) -+ -+#define DEVCFG_TOUCH_MASK 0x3f -+#define DEVCFG_TOUCH_ENABLE BIT(0) -+#define DEVCFG_TOUCH_PROP_DATA_ENABLE BIT(1) -+#define DEVCFG_TOUCH_HID_REPORT_ENABLE BIT(2) -+#define DEVCFG_TOUCH_POWER_STATE(x) (((x) & 7) << 3) -+#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) -+ -+#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" -+ -+#define DEVCFG_SPI_CLKDIV(x) (((x) >> 1) & 7) -+#define DEVCFG_SPI_CLKDIV_8 BIT(4) -+#define DEVCFG_SPI_SUPPORTS_SINGLE BIT(5) -+#define DEVCFG_SPI_SUPPORTS_DUAL BIT(6) -+#define DEVCFG_SPI_SUPPORTS_QUAD BIT(7) -+#define DEVCFG_SPI_MAX_TOUCH_POINTS(x) (((x) >> 8) & 0x3f) -+#define DEVCFG_SPI_MIN_RESET_TIME(x) (((x) >> 16) & 0xf) -+#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat -+#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) -+#define DEVCFG_SPI_UNKNOWN_25 BIT(25) -+#define DEVCFG_SPI_UNKNOWN_26 BIT(26) -+#define DEVCFG_SPI_UNKNOWN_27 BIT(27) -+#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this -+#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? -+ -+struct ithc_device_config { // (Example values are from an SP7+.) -+ u32 irq_cause; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) -+ u32 error; // 04 = 0x00000000 -+ u32 dma_buf_sizes; // 08 = 0x000a00ff -+ u32 touch_cfg; // 0c = 0x0000001c -+ u32 touch_state; // 10 = 0x0000001c -+ u32 device_id; // 14 = 0x43495424 = "$TIC" -+ u32 spi_config; // 18 = 0xfda00a2e -+ u16 vendor_id; // 1c = 0x045e = Microsoft Corp. -+ u16 product_id; // 1e = 0x0c1a -+ u32 revision; // 20 = 0x00000001 -+ u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) -+ u32 command; // 28 = 0x00000000 -+ u32 fw_mode; // 2c = 0x00000000 (for fw update?) -+ u32 _unknown_30; // 30 = 0x00000000 -+ u8 eds_minor_ver; // 34 = 0x5e -+ u8 eds_major_ver; // 35 = 0x03 -+ u8 interface_rev; // 36 = 0x04 -+ u8 eu_kernel_ver; // 37 = 0x04 -+ u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) -+ u32 _unknown_3c; // 3c = 0x00000002 -+}; -+static_assert(sizeof(struct ithc_device_config) == 64); -+ -+#define RX_CODE_INPUT_REPORT 3 -+#define RX_CODE_FEATURE_REPORT 4 -+#define RX_CODE_REPORT_DESCRIPTOR 5 -+#define RX_CODE_RESET 7 -+ -+#define TX_CODE_SET_FEATURE 3 -+#define TX_CODE_GET_FEATURE 4 -+#define TX_CODE_OUTPUT_REPORT 5 -+#define TX_CODE_GET_REPORT_DESCRIPTOR 7 -+ -+static int ithc_set_device_enabled(struct ithc *ithc, bool enable) -+{ -+ u32 x = ithc->legacy_touch_cfg = -+ (ithc->legacy_touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | -+ DEVCFG_TOUCH_HID_REPORT_ENABLE | -+ (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_POWER_STATE(3) : 0); -+ return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -+ offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); -+} -+ -+int ithc_legacy_init(struct ithc *ithc) -+{ -+ // Since we don't yet know which SPI config the device wants, use default speed and mode -+ // initially for reading config data. -+ CHECK(ithc_set_spi_config, ithc, 2, true, SPI_MODE_SINGLE, SPI_MODE_SINGLE); -+ -+ // Setting the following bit seems to make reading the config more reliable. -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); -+ -+ // Setting this bit may be necessary on some ADL devices. -+ switch (ithc->pci->device) { -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1: -+ case PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2: -+ bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_5); -+ break; -+ } -+ -+ // Take the touch device out of reset. -+ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -+ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -+ if (!waitl(ithc, &ithc->regs->irq_cause, 0xf, 2)) -+ break; -+ if (retries > 5) { -+ pci_err(ithc->pci, "failed to reset device, irq_cause = 0x%08x\n", -+ readl(&ithc->regs->irq_cause)); -+ return -ETIMEDOUT; -+ } -+ pci_warn(ithc->pci, "invalid irq_cause, retrying reset\n"); -+ bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -+ if (msleep_interruptible(1000)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); -+ -+ // Read configuration data. -+ u32 spi_cfg; -+ for (int retries = 0; ; retries++) { -+ ithc_log_regs(ithc); -+ struct ithc_device_config config = { 0 }; -+ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(config), &config); -+ u32 *p = (void *)&config; -+ pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -+ if (config.device_id == DEVCFG_DEVICE_ID_TIC) { -+ spi_cfg = config.spi_config; -+ ithc->vendor_id = config.vendor_id; -+ ithc->product_id = config.product_id; -+ ithc->product_rev = config.revision; -+ ithc->max_rx_size = DEVCFG_DMA_RX_SIZE(config.dma_buf_sizes); -+ ithc->max_tx_size = DEVCFG_DMA_TX_SIZE(config.dma_buf_sizes); -+ ithc->legacy_touch_cfg = config.touch_cfg; -+ ithc->have_config = true; -+ break; -+ } -+ if (retries > 10) { -+ pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -+ config.device_id); -+ return -EIO; -+ } -+ pci_warn(ithc->pci, "failed to read config, retrying\n"); -+ if (msleep_interruptible(100)) -+ return -EINTR; -+ } -+ ithc_log_regs(ithc); -+ -+ // Apply SPI config and enable touch device. -+ CHECK_RET(ithc_set_spi_config, ithc, -+ DEVCFG_SPI_CLKDIV(spi_cfg), (spi_cfg & DEVCFG_SPI_CLKDIV_8) != 0, -+ spi_cfg & DEVCFG_SPI_SUPPORTS_QUAD ? SPI_MODE_QUAD : -+ spi_cfg & DEVCFG_SPI_SUPPORTS_DUAL ? SPI_MODE_DUAL : -+ SPI_MODE_SINGLE, -+ SPI_MODE_SINGLE); -+ CHECK_RET(ithc_set_device_enabled, ithc, true); -+ ithc_log_regs(ithc); -+ return 0; -+} -+ -+void ithc_legacy_exit(struct ithc *ithc) -+{ -+ CHECK(ithc_set_device_enabled, ithc, false); -+} -+ -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) -+{ -+ const struct { -+ u32 code; -+ u32 data_size; -+ u32 _unknown[14]; -+ } *hdr = src; -+ -+ if (len < sizeof(*hdr)) -+ return -ENODATA; -+ // Note: RX data is not padded, even though TX data must be padded. -+ if (len != sizeof(*hdr) + hdr->data_size) -+ return -EMSGSIZE; -+ -+ dest->data = hdr + 1; -+ dest->size = hdr->data_size; -+ -+ switch (hdr->code) { -+ case RX_CODE_RESET: -+ // The THC sends a reset request when we need to reinitialize the device. -+ // This usually only happens if we send an invalid command or put the device -+ // in a bad state. -+ dest->type = ITHC_DATA_ERROR; -+ return 0; -+ case RX_CODE_REPORT_DESCRIPTOR: -+ // The descriptor is preceded by 8 nul bytes. -+ if (hdr->data_size < 8) -+ return -ENODATA; -+ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; -+ dest->data = (char *)(hdr + 1) + 8; -+ dest->size = hdr->data_size - 8; -+ return 0; -+ case RX_CODE_INPUT_REPORT: -+ dest->type = ITHC_DATA_INPUT_REPORT; -+ return 0; -+ case RX_CODE_FEATURE_REPORT: -+ dest->type = ITHC_DATA_GET_FEATURE; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen) ++static int ithc_thaw(struct device *dev) +{ -+ struct { -+ u32 code; -+ u32 data_size; -+ } *hdr = dest; -+ -+ size_t src_size = src->size; -+ const void *src_data = src->data; -+ const u64 get_report_desc_data = 0; -+ u32 code; -+ -+ switch (src->type) { -+ case ITHC_DATA_SET_FEATURE: -+ code = TX_CODE_SET_FEATURE; -+ break; -+ case ITHC_DATA_GET_FEATURE: -+ code = TX_CODE_GET_FEATURE; -+ break; -+ case ITHC_DATA_OUTPUT_REPORT: -+ code = TX_CODE_OUTPUT_REPORT; -+ break; -+ case ITHC_DATA_REPORT_DESCRIPTOR: -+ code = TX_CODE_GET_REPORT_DESCRIPTOR; -+ src_size = sizeof(get_report_desc_data); -+ src_data = &get_report_desc_data; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ // Data must be padded to next 4-byte boundary. -+ size_t padded = round_up(src_size, 4); -+ if (sizeof(*hdr) + padded > maxlen) -+ return -EOVERFLOW; -+ -+ // Fill the TX buffer with header and data. -+ hdr->code = code; -+ hdr->data_size = src_size; -+ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); -+ -+ return sizeof(*hdr) + padded; ++ struct pci_dev *pci = to_pci_dev(dev); ++ pci_dbg(pci, "pm thaw\n"); ++ return ithc_start(pci); +} + -diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h -new file mode 100644 -index 0000000000000..28d6924620722 ---- /dev/null -+++ b/drivers/hid/ithc/ithc-legacy.h -@@ -0,0 +1,8 @@ -+/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ -+ -+int ithc_legacy_init(struct ithc *ithc); -+void ithc_legacy_exit(struct ithc *ithc); -+int ithc_legacy_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); -+ssize_t ithc_legacy_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, -+ size_t maxlen); -+ -diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c -index 87ed4aa70fda0..2acf02e41d40f 100644 ---- a/drivers/hid/ithc/ithc-main.c -+++ b/drivers/hid/ithc/ithc-main.c -@@ -5,28 +5,6 @@ - MODULE_DESCRIPTION("Intel Touch Host Controller driver"); - MODULE_LICENSE("Dual BSD/GPL"); - --// Lakefield --#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 --#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 --// Tiger Lake --#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 --#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 --#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 --#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 --// Alder Lake --#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 --#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 --#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 --#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 --#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 --#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 --// Raptor Lake --#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 --#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 --// Meteor Lake --#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 --#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a -- - static const struct pci_device_id ithc_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THC_LKF_PORT2) }, -@@ -66,15 +44,13 @@ static bool ithc_use_rx1 = true; - module_param_named(rx1, ithc_use_rx1, bool, 0); - MODULE_PARM_DESC(rx1, "Use DMA RX channel 1"); - --// Values below 250 seem to work well on the SP7+. If this is set too high, you may observe cursor stuttering. --static int ithc_dma_latency_us = 200; --module_param_named(dma_latency_us, ithc_dma_latency_us, int, 0); --MODULE_PARM_DESC(dma_latency_us, "Determines the CPU latency QoS value for DMA transfers (in microseconds), -1 to disable latency QoS"); -+static int ithc_active_ltr_us = -1; -+module_param_named(activeltr, ithc_active_ltr_us, int, 0); -+MODULE_PARM_DESC(activeltr, "Active LTR value override (in microseconds)"); - --// Values above 1700 seem to work well on the SP7+. If this is set too low, you may observe cursor stuttering. --static unsigned int ithc_dma_early_us = 2000; --module_param_named(dma_early_us, ithc_dma_early_us, uint, 0); --MODULE_PARM_DESC(dma_early_us, "Determines how early the CPU latency QoS value is applied before the next expected IRQ (in microseconds)"); -+static int ithc_idle_ltr_us = -1; -+module_param_named(idleltr, ithc_idle_ltr_us, int, 0); -+MODULE_PARM_DESC(idleltr, "Idle LTR value override (in microseconds)"); - - static bool ithc_log_regs_enabled = false; - module_param_named(logregs, ithc_log_regs_enabled, bool, 0); -@@ -82,44 +58,30 @@ MODULE_PARM_DESC(logregs, "Log changes in register values (for debugging)"); - - // Sysfs attributes - --static bool ithc_is_config_valid(struct ithc *ithc) --{ -- return ithc->config.device_id == DEVCFG_DEVICE_ID_TIC; --} -- - static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "0x%04x", ithc->config.vendor_id); -+ return sprintf(buf, "0x%04x", ithc->vendor_id); - } - static DEVICE_ATTR_RO(vendor); - static ssize_t product_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "0x%04x", ithc->config.product_id); -+ return sprintf(buf, "0x%04x", ithc->product_id); - } - static DEVICE_ATTR_RO(product); - static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) - { - struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -+ if (!ithc || !ithc->have_config) - return -ENODEV; -- return sprintf(buf, "%u", ithc->config.revision); -+ return sprintf(buf, "%u", ithc->product_rev); - } - static DEVICE_ATTR_RO(revision); --static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) --{ -- struct ithc *ithc = dev_get_drvdata(dev); -- if (!ithc || !ithc_is_config_valid(ithc)) -- return -ENODEV; -- u32 v = ithc->config.fw_version; -- return sprintf(buf, "%i.%i.%i.%i", v >> 24, v >> 16 & 0xff, v >> 8 & 0xff, v & 0xff); --} --static DEVICE_ATTR_RO(fw_version); - - static const struct attribute_group *ithc_attribute_groups[] = { - &(const struct attribute_group){ -@@ -128,185 +90,26 @@ static const struct attribute_group *ithc_attribute_groups[] = { - &dev_attr_vendor.attr, - &dev_attr_product.attr, - &dev_attr_revision.attr, -- &dev_attr_fw_version.attr, - NULL - }, - }, - NULL - }; - --// HID setup -- --static int ithc_hid_start(struct hid_device *hdev) { return 0; } --static void ithc_hid_stop(struct hid_device *hdev) { } --static int ithc_hid_open(struct hid_device *hdev) { return 0; } --static void ithc_hid_close(struct hid_device *hdev) { } -- --static int ithc_hid_parse(struct hid_device *hdev) --{ -- struct ithc *ithc = hdev->driver_data; -- u64 val = 0; -- WRITE_ONCE(ithc->hid_parse_done, false); -- for (int retries = 0; ; retries++) { -- CHECK_RET(ithc_dma_tx, ithc, DMA_TX_CODE_GET_REPORT_DESCRIPTOR, sizeof(val), &val); -- if (wait_event_timeout(ithc->wait_hid_parse, READ_ONCE(ithc->hid_parse_done), -- msecs_to_jiffies(200))) -- return 0; -- if (retries > 5) { -- pci_err(ithc->pci, "failed to read report descriptor\n"); -- return -ETIMEDOUT; -- } -- pci_warn(ithc->pci, "failed to read report descriptor, retrying\n"); -- } --} -- --static int ithc_hid_raw_request(struct hid_device *hdev, unsigned char reportnum, __u8 *buf, -- size_t len, unsigned char rtype, int reqtype) --{ -- struct ithc *ithc = hdev->driver_data; -- if (!buf || !len) -- return -EINVAL; -- u32 code; -- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) { -- code = DMA_TX_CODE_OUTPUT_REPORT; -- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) { -- code = DMA_TX_CODE_SET_FEATURE; -- } else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) { -- code = DMA_TX_CODE_GET_FEATURE; -- } else { -- pci_err(ithc->pci, "unhandled hid request %i %i for report id %i\n", -- rtype, reqtype, reportnum); -- return -EINVAL; -- } -- buf[0] = reportnum; -- -- if (reqtype == HID_REQ_GET_REPORT) { -- // Prepare for response. -- mutex_lock(&ithc->hid_get_feature_mutex); -- ithc->hid_get_feature_buf = buf; -- ithc->hid_get_feature_size = len; -- mutex_unlock(&ithc->hid_get_feature_mutex); -- -- // Transmit 'get feature' request. -- int r = CHECK(ithc_dma_tx, ithc, code, 1, buf); -- if (!r) { -- r = wait_event_interruptible_timeout(ithc->wait_hid_get_feature, -- !ithc->hid_get_feature_buf, msecs_to_jiffies(1000)); -- if (!r) -- r = -ETIMEDOUT; -- else if (r < 0) -- r = -EINTR; -- else -- r = 0; -- } -- -- // If everything went ok, the buffer has been filled with the response data. -- // Return the response size. -- mutex_lock(&ithc->hid_get_feature_mutex); -- ithc->hid_get_feature_buf = NULL; -- if (!r) -- r = ithc->hid_get_feature_size; -- mutex_unlock(&ithc->hid_get_feature_mutex); -- return r; -- } -- -- // 'Set feature', or 'output report'. These don't have a response. -- CHECK_RET(ithc_dma_tx, ithc, code, len, buf); -- return 0; --} -- --static struct hid_ll_driver ithc_ll_driver = { -- .start = ithc_hid_start, -- .stop = ithc_hid_stop, -- .open = ithc_hid_open, -- .close = ithc_hid_close, -- .parse = ithc_hid_parse, -- .raw_request = ithc_hid_raw_request, --}; -- --static void ithc_hid_devres_release(struct device *dev, void *res) --{ -- struct hid_device **hidm = res; -- if (*hidm) -- hid_destroy_device(*hidm); --} -- --static int ithc_hid_init(struct ithc *ithc) --{ -- struct hid_device **hidm = devres_alloc(ithc_hid_devres_release, sizeof(*hidm), GFP_KERNEL); -- if (!hidm) -- return -ENOMEM; -- devres_add(&ithc->pci->dev, hidm); -- struct hid_device *hid = hid_allocate_device(); -- if (IS_ERR(hid)) -- return PTR_ERR(hid); -- *hidm = hid; -- -- strscpy(hid->name, DEVFULLNAME, sizeof(hid->name)); -- strscpy(hid->phys, ithc->phys, sizeof(hid->phys)); -- hid->ll_driver = &ithc_ll_driver; -- hid->bus = BUS_PCI; -- hid->vendor = ithc->config.vendor_id; -- hid->product = ithc->config.product_id; -- hid->version = 0x100; -- hid->dev.parent = &ithc->pci->dev; -- hid->driver_data = ithc; -- -- ithc->hid = hid; -- return 0; --} -- - // Interrupts/polling - --static enum hrtimer_restart ithc_activity_start_timer_callback(struct hrtimer *t) --{ -- struct ithc *ithc = container_of(t, struct ithc, activity_start_timer); -- ithc_set_active(ithc, ithc_dma_early_us * 2 + USEC_PER_MSEC); -- return HRTIMER_NORESTART; --} -- --static enum hrtimer_restart ithc_activity_end_timer_callback(struct hrtimer *t) --{ -- struct ithc *ithc = container_of(t, struct ithc, activity_end_timer); -- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- return HRTIMER_NORESTART; --} -- --void ithc_set_active(struct ithc *ithc, unsigned int duration_us) --{ -- if (ithc_dma_latency_us < 0) -- return; -- // When CPU usage is very low, the CPU can enter various low power states (C2-C10). -- // This disrupts DMA, causing truncated DMA messages. ERROR_FLAG_DMA_RX_TIMEOUT will be -- // set when this happens. The amount of truncated messages can become very high, resulting -- // in user-visible effects (laggy/stuttering cursor). To avoid this, we use a CPU latency -- // QoS request to prevent the CPU from entering low power states during touch interactions. -- cpu_latency_qos_update_request(&ithc->activity_qos, ithc_dma_latency_us); -- hrtimer_start_range_ns(&ithc->activity_end_timer, -- ns_to_ktime(duration_us * NSEC_PER_USEC), duration_us * NSEC_PER_USEC, HRTIMER_MODE_REL); --} -- --static int ithc_set_device_enabled(struct ithc *ithc, bool enable) --{ -- u32 x = ithc->config.touch_cfg = -- (ithc->config.touch_cfg & ~(u32)DEVCFG_TOUCH_MASK) | DEVCFG_TOUCH_UNKNOWN_2 | -- (enable ? DEVCFG_TOUCH_ENABLE | DEVCFG_TOUCH_UNKNOWN_3 | DEVCFG_TOUCH_UNKNOWN_4 : 0); -- return ithc_spi_command(ithc, SPI_CMD_CODE_WRITE, -- offsetof(struct ithc_device_config, touch_cfg), sizeof(x), &x); --} -- - static void ithc_disable_interrupts(struct ithc *ithc) - { - writel(0, &ithc->regs->error_control); - bitsb(&ithc->regs->spi_cmd.control, SPI_CMD_CONTROL_IRQ, 0); -- bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -- bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_UNKNOWN_4 | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[0].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); -+ bitsb(&ithc->regs->dma_rx[1].control, DMA_RX_CONTROL_IRQ_UNKNOWN_1 | DMA_RX_CONTROL_IRQ_ERROR | DMA_RX_CONTROL_IRQ_READY | DMA_RX_CONTROL_IRQ_DATA, 0); - bitsb(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_IRQ, 0); - } - - static void ithc_clear_dma_rx_interrupts(struct ithc *ithc, unsigned int channel) - { -- writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_UNKNOWN_4 | DMA_RX_STATUS_HAVE_DATA, -+ writel(DMA_RX_STATUS_ERROR | DMA_RX_STATUS_READY | DMA_RX_STATUS_HAVE_DATA, - &ithc->regs->dma_rx[channel].status); - } - -@@ -325,39 +128,22 @@ static void ithc_process(struct ithc *ithc) - { - ithc_log_regs(ithc); - -+ // The THC automatically transitions from LTR idle to active at the start of a DMA transfer. -+ // It does not appear to automatically go back to idle, so we switch it back here, since -+ // the DMA transfer should be complete. -+ ithc_set_ltr_idle(ithc); -+ - bool rx0 = ithc_use_rx0 && (readl(&ithc->regs->dma_rx[0].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; - bool rx1 = ithc_use_rx1 && (readl(&ithc->regs->dma_rx[1].status) & (DMA_RX_STATUS_ERROR | DMA_RX_STATUS_HAVE_DATA)) != 0; - -- // Track time between DMA rx transfers, so we can try to predict when we need to enable CPU latency QoS for the next transfer -- ktime_t t = ktime_get(); -- ktime_t dt = ktime_sub(t, ithc->last_rx_time); -- if (rx0 || rx1) { -- ithc->last_rx_time = t; -- if (dt > ms_to_ktime(100)) { -- ithc->cur_rx_seq_count = 0; -- ithc->cur_rx_seq_errors = 0; -- } -- ithc->cur_rx_seq_count++; -- if (!ithc_use_polling && ithc_dma_latency_us >= 0) { -- // Disable QoS, since the DMA transfer has completed (we re-enable it after a delay below) -- cpu_latency_qos_update_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- hrtimer_try_to_cancel(&ithc->activity_end_timer); -- } -- } -- - // Read and clear error bits - u32 err = readl(&ithc->regs->error_flags); - if (err) { - writel(err, &ithc->regs->error_flags); - if (err & ~ERROR_FLAG_DMA_RX_TIMEOUT) - pci_err(ithc->pci, "error flags: 0x%08x\n", err); -- if (err & ERROR_FLAG_DMA_RX_TIMEOUT) { -- // Only log an error if we see a significant number of these errors. -- ithc->cur_rx_seq_errors++; -- if (ithc->cur_rx_seq_errors && ithc->cur_rx_seq_errors % 50 == 0 && ithc->cur_rx_seq_errors > ithc->cur_rx_seq_count / 10) -- pci_err(ithc->pci, "High number of DMA RX timeouts/errors (%u/%u, dt=%lldus). Try adjusting dma_early_us and/or dma_latency_us.\n", -- ithc->cur_rx_seq_errors, ithc->cur_rx_seq_count, ktime_to_us(dt)); -- } -+ if (err & ERROR_FLAG_DMA_RX_TIMEOUT) -+ pci_err(ithc->pci, "DMA RX timeout/error (try decreasing activeltr/idleltr if this happens frequently)\n"); - } - - // Process DMA rx -@@ -372,12 +158,6 @@ static void ithc_process(struct ithc *ithc) - ithc_dma_rx(ithc, 1); - } - -- // Start timer to re-enable QoS for next rx, but only if we've seen an ERROR_FLAG_DMA_RX_TIMEOUT -- if ((rx0 || rx1) && !ithc_use_polling && ithc_dma_latency_us >= 0 && ithc->cur_rx_seq_errors > 0) { -- ktime_t expires = ktime_add(t, ktime_sub_us(dt, ithc_dma_early_us)); -- hrtimer_start_range_ns(&ithc->activity_start_timer, expires, 10 * NSEC_PER_USEC, HRTIMER_MODE_ABS); -- } -- - ithc_log_regs(ithc); - } - -@@ -403,12 +183,8 @@ static int ithc_poll_thread(void *arg) - ithc_process(ithc); - // Decrease polling interval to 20ms if we received data, otherwise slowly - // increase it up to 200ms. -- if (n != ithc->dma_rx[1].num_received) { -- ithc_set_active(ithc, 100 * USEC_PER_MSEC); -- sleep = 20; -- } else { -- sleep = min(200u, sleep + (sleep >> 4) + 1); -- } -+ sleep = n != ithc->dma_rx[1].num_received ? 20 -+ : min(200u, sleep + (sleep >> 4) + 1); - msleep_interruptible(sleep); - } - return 0; -@@ -431,73 +207,44 @@ static void ithc_disable(struct ithc *ithc) - - static int ithc_init_device(struct ithc *ithc) - { -+ // Read ACPI config for QuickSPI mode -+ struct ithc_acpi_config cfg = { 0 }; -+ CHECK_RET(ithc_read_acpi_config, ithc, &cfg); -+ if (!cfg.has_config) -+ pci_info(ithc->pci, "no ACPI config, using legacy mode\n"); -+ else -+ ithc_print_acpi_config(ithc, &cfg); -+ ithc->use_quickspi = cfg.has_config; -+ -+ // Shut down device - ithc_log_regs(ithc); - bool was_enabled = (readl(&ithc->regs->control_bits) & CONTROL_NRESET) != 0; - ithc_disable(ithc); - CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_READY, CONTROL_READY); -- -- // Since we don't yet know which SPI config the device wants, use default speed and mode -- // initially for reading config data. -- ithc_set_spi_config(ithc, 10, 0); -- -- // Setting the following bit seems to make reading the config more reliable. -- bitsl_set(&ithc->regs->dma_rx[0].unknown_init_bits, 0x80000000); -+ ithc_log_regs(ithc); - - // If the device was previously enabled, wait a bit to make sure it's fully shut down. - if (was_enabled) - if (msleep_interruptible(100)) - return -EINTR; - -- // Take the touch device out of reset. -- bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); -- CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, 0); -- for (int retries = 0; ; retries++) { -- ithc_log_regs(ithc); -- bitsl_set(&ithc->regs->control_bits, CONTROL_NRESET); -- if (!waitl(ithc, &ithc->regs->state, 0xf, 2)) -- break; -- if (retries > 5) { -- pci_err(ithc->pci, "failed to reset device, state = 0x%08x\n", readl(&ithc->regs->state)); -- return -ETIMEDOUT; -- } -- pci_warn(ithc->pci, "invalid state, retrying reset\n"); -- bitsl(&ithc->regs->control_bits, CONTROL_NRESET, 0); -- if (msleep_interruptible(1000)) -- return -EINTR; -- } -- ithc_log_regs(ithc); -+ // Set Latency Tolerance Reporting config. The device will automatically -+ // apply these values depending on whether it is active or idle. -+ // If active value is too high, DMA buffer data can become truncated. -+ // By default, we set the active LTR value to 100us, and idle to 100ms. -+ u64 active_ltr_ns = ithc_active_ltr_us >= 0 ? (u64)ithc_active_ltr_us * 1000 -+ : cfg.has_config && cfg.has_active_ltr ? (u64)cfg.active_ltr << 10 -+ : 100 * 1000; -+ u64 idle_ltr_ns = ithc_idle_ltr_us >= 0 ? (u64)ithc_idle_ltr_us * 1000 -+ : cfg.has_config && cfg.has_idle_ltr ? (u64)cfg.idle_ltr << 10 -+ : 100 * 1000 * 1000; -+ ithc_set_ltr_config(ithc, active_ltr_ns, idle_ltr_ns); -+ -+ if (ithc->use_quickspi) -+ CHECK_RET(ithc_quickspi_init, ithc, &cfg); -+ else -+ CHECK_RET(ithc_legacy_init, ithc); - -- // Waiting for the following status bit makes reading config much more reliable, -- // however the official driver does not seem to do this... -- CHECK(waitl, ithc, &ithc->regs->dma_rx[0].status, DMA_RX_STATUS_UNKNOWN_4, DMA_RX_STATUS_UNKNOWN_4); -- -- // Read configuration data. -- for (int retries = 0; ; retries++) { -- ithc_log_regs(ithc); -- memset(&ithc->config, 0, sizeof(ithc->config)); -- CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, 0, sizeof(ithc->config), &ithc->config); -- u32 *p = (void *)&ithc->config; -- pci_info(ithc->pci, "config: %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", -- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); -- if (ithc_is_config_valid(ithc)) -- break; -- if (retries > 10) { -- pci_err(ithc->pci, "failed to read config, unknown device ID 0x%08x\n", -- ithc->config.device_id); -- return -EIO; -- } -- pci_warn(ithc->pci, "failed to read config, retrying\n"); -- if (msleep_interruptible(100)) -- return -EINTR; -- } -- ithc_log_regs(ithc); -- -- // Apply SPI config and enable touch device. -- CHECK_RET(ithc_set_spi_config, ithc, -- DEVCFG_SPI_MAX_FREQ(ithc->config.spi_config), -- DEVCFG_SPI_MODE(ithc->config.spi_config)); -- CHECK_RET(ithc_set_device_enabled, ithc, true); -- ithc_log_regs(ithc); - return 0; - } - -@@ -527,11 +274,11 @@ static void ithc_stop(void *res) - CHECK(kthread_stop, ithc->poll_thread); - if (ithc->irq >= 0) - disable_irq(ithc->irq); -- CHECK(ithc_set_device_enabled, ithc, false); -+ if (ithc->use_quickspi) -+ ithc_quickspi_exit(ithc); -+ else -+ ithc_legacy_exit(ithc); - ithc_disable(ithc); -- hrtimer_cancel(&ithc->activity_start_timer); -- hrtimer_cancel(&ithc->activity_end_timer); -- cpu_latency_qos_remove_request(&ithc->activity_qos); - - // Clear DMA config. - for (unsigned int i = 0; i < 2; i++) { -@@ -570,9 +317,6 @@ static int ithc_start(struct pci_dev *pci) - ithc->irq = -1; - ithc->pci = pci; - snprintf(ithc->phys, sizeof(ithc->phys), "pci-%s/" DEVNAME, pci_name(pci)); -- init_waitqueue_head(&ithc->wait_hid_parse); -- init_waitqueue_head(&ithc->wait_hid_get_feature); -- mutex_init(&ithc->hid_get_feature_mutex); - pci_set_drvdata(pci, ithc); - CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_clear_drvdata, pci); - if (ithc_log_regs_enabled) -@@ -596,6 +340,9 @@ static int ithc_start(struct pci_dev *pci) - - // Initialize THC and touch device. - CHECK_RET(ithc_init_device, ithc); -+ -+ // Initialize HID and DMA. -+ CHECK_RET(ithc_hid_init, ithc); - CHECK(devm_device_add_groups, &pci->dev, ithc_attribute_groups); - if (ithc_use_rx0) - CHECK_RET(ithc_dma_rx_init, ithc, 0); -@@ -603,18 +350,10 @@ static int ithc_start(struct pci_dev *pci) - CHECK_RET(ithc_dma_rx_init, ithc, 1); - CHECK_RET(ithc_dma_tx_init, ithc); - -- cpu_latency_qos_add_request(&ithc->activity_qos, PM_QOS_DEFAULT_VALUE); -- hrtimer_init(&ithc->activity_start_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); -- ithc->activity_start_timer.function = ithc_activity_start_timer_callback; -- hrtimer_init(&ithc->activity_end_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -- ithc->activity_end_timer.function = ithc_activity_end_timer_callback; -- - // Add ithc_stop() callback AFTER setting up DMA buffers, so that polling/irqs/DMA are - // disabled BEFORE the buffers are freed. - CHECK_RET(devm_add_action_or_reset, &pci->dev, ithc_stop, ithc); - -- CHECK_RET(ithc_hid_init, ithc); -- - // Start polling/IRQ. - if (ithc_use_polling) { - pci_info(pci, "using polling instead of irq\n"); -@@ -637,9 +376,11 @@ static int ithc_start(struct pci_dev *pci) - - // hid_add_device() can only be called after irq/polling is started and DMA is enabled, - // because it calls ithc_hid_parse() which reads the report descriptor via DMA. -- CHECK_RET(hid_add_device, ithc->hid); -+ CHECK_RET(hid_add_device, ithc->hid.dev); ++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); ++} + -+ 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, - }, ++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 --#include --#include +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ +#include +#include +#include - #include ++#include +#include - #include --#include ++#include +#include - #include - #include --#include - #include - #include --#include ++#include ++#include ++#include ++#include +#include +#include - #include --#include --#include - - #define DEVNAME "ithc" - #define DEVFULLNAME "Intel Touch Host Controller" -@@ -27,10 +26,37 @@ - - #define NUM_RX_BUF 16 - ++#include ++#include ++#include ++ ++#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 -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 -Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@gmail.com/ -Tested-by: Weifeng Liu -Signed-off-by: Hans de Goede -Link: https://lore.kernel.org/r/20240509141549.63704-1-hdegoede@redhat.com -Signed-off-by: Greg Kroah-Hartman -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 -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 -Reviewed-by: Andy Shevchenko -Signed-off-by: Weifeng Liu -Link: https://lore.kernel.org/r/20240505130800.2546640-3-weifeng.liu.z@gmail.com -Reviewed-by: Hans de Goede -Signed-off-by: Hans de Goede -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 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 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 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 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 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 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 -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 - -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 -Patchset: surface-sam ---- - drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 34df1bdad83bd..c0bf0cadcd258 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[] = { - &ssam_node_bat_ac, - &ssam_node_bat_main, - &ssam_node_tmp_pprof, -+ &ssam_node_tmp_sensors, - &ssam_node_fan_speed, - &ssam_node_pos_tablet_switch, - &ssam_node_hid_kip_keyboard, --- -2.45.1 +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 -From 06c4b5ac6b6357227e45c53643729140d794b48d Mon Sep 17 00:00:00 2001 -From: Ivor Wanders -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. - -Signed-off-by: Ivor Wanders 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 ---- 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[] = { - &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_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[] = { +index 70a2ea5a1957..6b568804f70b 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -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, - NULL, - }; - -@@ -319,7 +333,7 @@ static const struct software_node *ssam_node_group_sp7[] = { +- &ssam_node_tmp_perf_profile, ++ &ssam_node_tmp_perf_profile_with_fan, ++ &ssam_node_tmp_sensors, ++ &ssam_node_fan_speed, + &ssam_node_hid_main_keyboard, + &ssam_node_hid_main_touchpad, + &ssam_node_hid_main_iid5, +-- +2.45.2 + +From 3175ecd829a778ffef35956d8785877bb76fe4b0 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +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 + +Patchset: surface-sam +--- + 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 6b568804f70b..9046df95c043 100644 +--- a/drivers/platform/surface/surface_aggregator_registry.c ++++ b/drivers/platform/surface/surface_aggregator_registry.c +@@ -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, - 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, + &ssam_node_tmp_perf_profile_with_fan, - &ssam_node_tmp_sensors, - &ssam_node_fan_speed, ++ &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 - */ -@@ -14,6 +14,7 @@ - - #include - -+// 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, + &ssam_node_hid_sam_keyboard, + &ssam_node_hid_sam_penstash, +-- +2.45.2 + +From aeef49471d7ec17f243c685b85c0c870c99e9e3d Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +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, }; -+// 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, ++/* 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, ++ &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); + /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ - status = ssam_tmp_profile_get(tpd->sdev, &tp); - if (status) - return status; +@@ -399,6 +418,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Pro 9 */ + { "MSHW0343", (unsigned long)ssam_node_group_sp9 }, -- 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; - -- tp = convert_profile_to_ssam(tpd->sdev, profile); -+ tp = ssam_tmp_profile_set(tpd->sdev, tp); - if (tp < 0) - return tp; - -- 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; - } + /* Surface Book 2 */ + { "MSHW0107", (unsigned long)ssam_node_group_gen5 }, - 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; - -+ 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 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 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 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 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 +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 +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?= +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 + #include + #include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -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 +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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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" 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 -- cgit v1.2.3