diff options
Diffstat (limited to 'SOURCES/linux-surface.patch')
-rw-r--r-- | SOURCES/linux-surface.patch | 4622 |
1 files changed, 3165 insertions, 1457 deletions
diff --git a/SOURCES/linux-surface.patch b/SOURCES/linux-surface.patch index ac7daa5..925163b 100644 --- a/SOURCES/linux-surface.patch +++ b/SOURCES/linux-surface.patch @@ -1,4 +1,41 @@ -From 45a9e7f97fc36942e3d70a78fe5313fa78733933 Mon Sep 17 00:00:00 2001 +From 24686c656a230f642f8ed6c09c184660c08cf46c Mon Sep 17 00:00:00 2001 +From: Maximilian Luz <luzmaximilian@gmail.com> +Date: Sun, 9 Jun 2024 19:48:58 +0200 +Subject: [PATCH] Revert "efi/x86: Set the PE/COFF header's NX compat flag + unconditionally" + +This reverts commit 891f8890a4a3663da7056542757022870b499bc1. + +Revert because of compatibility issues of MS Surface devices and GRUB +with NX. In short, these devices get stuck on boot with NX advertised. +So to not advertise it, add the respective option back in. + +Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> +Patchset: secureboot +--- + arch/x86/boot/header.S | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S +index b5c79f43359bc..a1bbedd989e42 100644 +--- a/arch/x86/boot/header.S ++++ b/arch/x86/boot/header.S +@@ -111,7 +111,11 @@ extra_header_fields: + .long salign # SizeOfHeaders + .long 0 # CheckSum + .word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application) ++#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES + .word IMAGE_DLL_CHARACTERISTICS_NX_COMPAT # DllCharacteristics ++#else ++ .word 0 # DllCharacteristics ++#endif + #ifdef CONFIG_X86_32 + .long 0 # SizeOfStackReserve + .long 0 # SizeOfStackCommit +-- +2.45.1 + +From a494cdb84ee162accff966a0012992e36e4b0c0a Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto <kitakar@gmail.com> Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI @@ -40,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 c15ed7a12784..1ec8edb5aafa 100644 +index c15ed7a12784a..1ec8edb5aafaf 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[] = { @@ -58,10 +95,10 @@ index c15ed7a12784..1ec8edb5aafa 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 20191a4473c2..5ba599b5aba6 100644 +index d0d24a53df746..43e06166a5d95 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c -@@ -3768,6 +3768,15 @@ static const struct dmi_system_id dmi_platform_data[] = { +@@ -3777,6 +3777,15 @@ static const struct dmi_system_id dmi_platform_data[] = { }, .driver_data = (void *)&intel_braswell_platform_data, }, @@ -78,7 +115,7 @@ index 20191a4473c2..5ba599b5aba6 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 5e2ec60e2954..207868c699f2 100644 +index 5e2ec60e2954b..207868c699f29 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[] = { @@ -97,9 +134,9 @@ index 5e2ec60e2954..207868c699f2 100644 }; -- -2.44.0 +2.45.1 -From 2c7ff35a85341dcd8fa2ea575088881df9dea874 Mon Sep 17 00:00:00 2001 +From 1abf1feb3b521abe9f9c9e8d68d2014e90ecb20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl> Date: Tue, 3 Nov 2020 13:28:04 +0100 Subject: [PATCH] mwifiex: Add quirk resetting the PCI bridge on MS Surface @@ -133,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 5f997becdbaa..9a9929424513 100644 +index 5f997becdbaa2..9a9929424513a 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) @@ -159,7 +196,7 @@ index 5f997becdbaa..9a9929424513 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 dd6d21f1dbfd..f46b06f8d643 100644 +index dd6d21f1dbfd7..f46b06f8d6435 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[] = { @@ -252,7 +289,7 @@ index dd6d21f1dbfd..f46b06f8d643 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 d6ff964aec5b..5d30ae39d65e 100644 +index d6ff964aec5bf..5d30ae39d65ec 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -4,6 +4,7 @@ @@ -264,9 +301,9 @@ index d6ff964aec5b..5d30ae39d65e 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.44.0 +2.45.1 -From 4a326d9e87d1dc4945903560d3d22fbd69a8962c Mon Sep 17 00:00:00 2001 +From 0574bff98f5f5af132783f8f72e8ef22e3f36097 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto <kitakar@gmail.com> Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -288,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 9a9929424513..2273e3029776 100644 +index 9a9929424513a..2273e30297766 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, @@ -313,7 +350,7 @@ index 9a9929424513..2273e3029776 100644 } diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 +index f46b06f8d6435..99b024ecbadea 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[] = { @@ -407,7 +444,7 @@ index f46b06f8d643..99b024ecbade 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 5d30ae39d65e..c14eb56eb911 100644 +index 5d30ae39d65ec..c14eb56eb9118 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -5,6 +5,7 @@ @@ -419,9 +456,9 @@ index 5d30ae39d65e..c14eb56eb911 100644 void mwifiex_initialize_quirks(struct pcie_service_card *card); int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); -- -2.44.0 +2.45.1 -From dddda6f9c25716dea1265f71b8286936afa192b5 Mon Sep 17 00:00:00 2001 +From 8a4ee131ced8068371a8fa09da17d82414e6d835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl> Date: Thu, 25 Mar 2021 11:33:02 +0100 Subject: [PATCH] Bluetooth: btusb: Lower passive lescan interval on Marvell @@ -457,7 +494,7 @@ Patchset: mwifiex 1 file changed, 15 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index d31edad7a056..fc08e0c51c87 100644 +index fb716849b60f3..1e7b3798108f7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -476,7 +513,7 @@ index d31edad7a056..fc08e0c51c87 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4401,6 +4403,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4417,6 +4419,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -497,9 +534,9 @@ index d31edad7a056..fc08e0c51c87 100644 (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; -- -2.44.0 +2.45.1 -From 7b414f11dfa0be3204b0a43b82a75744f8218d57 Mon Sep 17 00:00:00 2001 +From fc56de38d725edc7c3856c2a2d369e1f170f202f Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 27 Feb 2021 00:45:52 +0100 Subject: [PATCH] ath10k: Add module parameters to override board files @@ -521,7 +558,7 @@ Patchset: ath10k 1 file changed, 58 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 0032f8aa892f..17717b53316b 100644 +index fa5e2e6518313..8921b0ebf36b7 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; @@ -554,7 +591,7 @@ index 0032f8aa892f..17717b53316b 100644 static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, -@@ -928,6 +937,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) +@@ -931,6 +940,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) return 0; } @@ -597,7 +634,7 @@ index 0032f8aa892f..17717b53316b 100644 static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, const char *dir, const char *file) -@@ -942,6 +987,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, +@@ -945,6 +990,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, if (dir == NULL) dir = "."; @@ -618,9 +655,9 @@ index 0032f8aa892f..17717b53316b 100644 ret = firmware_request_nowarn(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", -- -2.44.0 +2.45.1 -From 4a1fdfebd3e84fe581b512f73bbc551ec9e2d0e8 Mon Sep 17 00:00:00 2001 +From ee272e8a81f073b5475a3bb2c3085b55f181bc24 Mon Sep 17 00:00:00 2001 From: Dorian Stoll <dorian.stoll@tmsp.io> Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] mei: me: Add Icelake device ID for iTouch @@ -633,7 +670,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 aac36750d2c5..2ba8db8a9583 100644 +index c3a6657dcd4a2..82eef2f4eb0a8 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -92,6 +92,7 @@ @@ -645,7 +682,7 @@ index aac36750d2c5..2ba8db8a9583 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 8cf636c54032..078d3e773cda 100644 +index 7f59dd38c32f5..a56ad5b3f7790 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[] = { @@ -657,9 +694,9 @@ index 8cf636c54032..078d3e773cda 100644 {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, -- -2.44.0 +2.45.1 -From b1e22125c8f241f49cc3a6b7eaa0b6430bb1f1ce Mon Sep 17 00:00:00 2001 +From 8536601cfc6d7671f4c11cab4dca57674f59b349 Mon Sep 17 00:00:00 2001 From: Liban Hannan <liban.p@gmail.com> Date: Tue, 12 Apr 2022 23:31:12 +0100 Subject: [PATCH] iommu: Use IOMMU passthrough mode for IPTS @@ -683,10 +720,10 @@ Patchset: ipts 1 file changed, 29 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 11652e0bcab3..6c01b1aebf27 100644 +index e4a03588a8a0f..61bc54299a591 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c -@@ -40,6 +40,11 @@ +@@ -39,6 +39,11 @@ #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) @@ -698,24 +735,24 @@ index 11652e0bcab3..6c01b1aebf27 100644 #define IOAPIC_RANGE_START (0xfee00000) #define IOAPIC_RANGE_END (0xfeefffff) #define IOVA_START_ADDR (0x1000) -@@ -148,12 +153,14 @@ int intel_iommu_enabled = 0; +@@ -221,12 +226,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); - static int dmar_map_gfx = 1; +static int dmar_map_ipts = 1; static int intel_iommu_superpage = 1; static int iommu_identity_mapping; static int iommu_skip_te_disable; + static int disable_igfx_iommu; - #define IDENTMAP_GFX 2 #define IDENTMAP_AZALIA 4 +#define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; static const struct iommu_dirty_ops intel_dirty_ops; -@@ -2412,6 +2419,9 @@ static int device_def_domain_type(struct device *dev) +@@ -2401,6 +2408,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; + + if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) @@ -723,9 +760,9 @@ index 11652e0bcab3..6c01b1aebf27 100644 } return 0; -@@ -2719,6 +2729,9 @@ static int __init init_dmars(void) - if (!dmar_map_gfx) - iommu_identity_mapping |= IDENTMAP_GFX; +@@ -2701,6 +2711,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + if (!dmar_map_ipts) + iommu_identity_mapping |= IDENTMAP_IPTS; @@ -733,8 +770,8 @@ index 11652e0bcab3..6c01b1aebf27 100644 check_tylersburg_isoch(); ret = si_domain_init(hw_pass_through); -@@ -4896,6 +4909,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - dmar_map_gfx = 0; +@@ -4871,6 +4884,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; } +static void quirk_iommu_ipts(struct pci_dev *dev) @@ -752,7 +789,7 @@ index 11652e0bcab3..6c01b1aebf27 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); -@@ -4931,6 +4956,10 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4906,6 +4931,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); @@ -764,9 +801,9 @@ index 11652e0bcab3..6c01b1aebf27 100644 { if (risky_device(dev)) -- -2.44.0 +2.45.1 -From fa7796bc06659b87f47d8921d0441314612870b9 Mon Sep 17 00:00:00 2001 +From 664128ab9984f6c774d4064548d9b247041d2520 Mon Sep 17 00:00:00 2001 From: Dorian Stoll <dorian.stoll@tmsp.io> Date: Sun, 11 Dec 2022 12:00:59 +0100 Subject: [PATCH] hid: Add support for Intel Precise Touch and Stylus @@ -833,7 +870,7 @@ Patchset: ipts create mode 100644 drivers/hid/ipts/thread.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4c682c650704..a263e49b2ae2 100644 +index 4c682c6507040..a263e49b2ae29 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1351,4 +1351,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" @@ -844,7 +881,7 @@ index 4c682c650704..a263e49b2ae2 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 082a728eac60..f4bad1b8d813 100644 +index 082a728eac600..f4bad1b8d813f 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -170,3 +170,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ @@ -855,7 +892,7 @@ index 082a728eac60..f4bad1b8d813 100644 +obj-$(CONFIG_HID_IPTS) += ipts/ diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 0000000000000..297401bd388dd --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -875,7 +912,7 @@ index 000000000000..297401bd388d + module will be called ipts. diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile new file mode 100644 -index 000000000000..883896f68e6a +index 0000000000000..883896f68e6ad --- /dev/null +++ b/drivers/hid/ipts/Makefile @@ -0,0 +1,16 @@ @@ -897,7 +934,7 @@ index 000000000000..883896f68e6a +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..63a4934bbc5f +index 0000000000000..63a4934bbc5fa --- /dev/null +++ b/drivers/hid/ipts/cmd.c @@ -0,0 +1,61 @@ @@ -964,7 +1001,7 @@ index 000000000000..63a4934bbc5f +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..2b4079075b64 +index 0000000000000..2b4079075b642 --- /dev/null +++ b/drivers/hid/ipts/cmd.h @@ -0,0 +1,60 @@ @@ -1030,7 +1067,7 @@ index 000000000000..2b4079075b64 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..ba33259f1f7c +index 0000000000000..ba33259f1f7c5 --- /dev/null +++ b/drivers/hid/ipts/context.h @@ -0,0 +1,52 @@ @@ -1088,7 +1125,7 @@ index 000000000000..ba33259f1f7c +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..5360842d260b +index 0000000000000..5360842d260ba --- /dev/null +++ b/drivers/hid/ipts/control.c @@ -0,0 +1,486 @@ @@ -1580,7 +1617,7 @@ index 000000000000..5360842d260b +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..26629c5144ed +index 0000000000000..26629c5144edb --- /dev/null +++ b/drivers/hid/ipts/control.h @@ -0,0 +1,126 @@ @@ -1712,7 +1749,7 @@ index 000000000000..26629c5144ed +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..307438c7c80c +index 0000000000000..307438c7c80cd --- /dev/null +++ b/drivers/hid/ipts/desc.h @@ -0,0 +1,80 @@ @@ -1798,7 +1835,7 @@ index 000000000000..307438c7c80c +#endif /* IPTS_DESC_H */ diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..ecbb3a8bdaf6 +index 0000000000000..ecbb3a8bdaf60 --- /dev/null +++ b/drivers/hid/ipts/eds1.c @@ -0,0 +1,103 @@ @@ -1907,7 +1944,7 @@ index 000000000000..ecbb3a8bdaf6 +} diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h new file mode 100644 -index 000000000000..eeeb6575e3e8 +index 0000000000000..eeeb6575e3e89 --- /dev/null +++ b/drivers/hid/ipts/eds1.h @@ -0,0 +1,35 @@ @@ -1948,7 +1985,7 @@ index 000000000000..eeeb6575e3e8 + 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 000000000000..198dc65d7887 +index 0000000000000..198dc65d78876 --- /dev/null +++ b/drivers/hid/ipts/eds2.c @@ -0,0 +1,144 @@ @@ -2098,7 +2135,7 @@ index 000000000000..198dc65d7887 +} diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h new file mode 100644 -index 000000000000..064e3716907a +index 0000000000000..064e3716907ab --- /dev/null +++ b/drivers/hid/ipts/eds2.h @@ -0,0 +1,35 @@ @@ -2139,7 +2176,7 @@ index 000000000000..064e3716907a + 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 000000000000..e34a1a4f9fa7 +index 0000000000000..e34a1a4f9fa77 --- /dev/null +++ b/drivers/hid/ipts/hid.c @@ -0,0 +1,225 @@ @@ -2370,7 +2407,7 @@ index 000000000000..e34a1a4f9fa7 +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..1ebe77447903 +index 0000000000000..1ebe77447903a --- /dev/null +++ b/drivers/hid/ipts/hid.h @@ -0,0 +1,24 @@ @@ -2400,7 +2437,7 @@ index 000000000000..1ebe77447903 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..fb5b5c13ee3e +index 0000000000000..fb5b5c13ee3ea --- /dev/null +++ b/drivers/hid/ipts/main.c @@ -0,0 +1,126 @@ @@ -2532,7 +2569,7 @@ index 000000000000..fb5b5c13ee3e +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..1e0395ceae4a +index 0000000000000..1e0395ceae4a4 --- /dev/null +++ b/drivers/hid/ipts/mei.c @@ -0,0 +1,188 @@ @@ -2726,7 +2763,7 @@ index 000000000000..1e0395ceae4a +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..973bade6b0fd +index 0000000000000..973bade6b0fdd --- /dev/null +++ b/drivers/hid/ipts/mei.h @@ -0,0 +1,66 @@ @@ -2798,7 +2835,7 @@ index 000000000000..973bade6b0fd +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..ef66c3c9db80 +index 0000000000000..ef66c3c9db807 --- /dev/null +++ b/drivers/hid/ipts/receiver.c @@ -0,0 +1,250 @@ @@ -3054,7 +3091,7 @@ index 000000000000..ef66c3c9db80 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..3de7da62d40c +index 0000000000000..3de7da62d40c1 --- /dev/null +++ b/drivers/hid/ipts/receiver.h @@ -0,0 +1,16 @@ @@ -3076,7 +3113,7 @@ index 000000000000..3de7da62d40c +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..cc14653b2a9f +index 0000000000000..cc14653b2a9f5 --- /dev/null +++ b/drivers/hid/ipts/resources.c @@ -0,0 +1,131 @@ @@ -3213,7 +3250,7 @@ index 000000000000..cc14653b2a9f +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..2068e13285f0 +index 0000000000000..2068e13285f0e --- /dev/null +++ b/drivers/hid/ipts/resources.h @@ -0,0 +1,41 @@ @@ -3260,7 +3297,7 @@ index 000000000000..2068e13285f0 +#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 000000000000..e8dd98895a7e +index 0000000000000..e8dd98895a7ee --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -3366,7 +3403,7 @@ index 000000000000..e8dd98895a7e +#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 000000000000..41845f9d9025 +index 0000000000000..41845f9d90257 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h @@ -0,0 +1,290 @@ @@ -3662,7 +3699,7 @@ index 000000000000..41845f9d9025 +#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 000000000000..5a58d4a0a610 +index 0000000000000..5a58d4a0a610f --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h @@ -0,0 +1,34 @@ @@ -3702,7 +3739,7 @@ index 000000000000..5a58d4a0a610 +#endif /* IPTS_SPEC_HID_H */ diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c new file mode 100644 -index 000000000000..355e92bea26f +index 0000000000000..355e92bea26f8 --- /dev/null +++ b/drivers/hid/ipts/thread.c @@ -0,0 +1,84 @@ @@ -3792,7 +3829,7 @@ index 000000000000..355e92bea26f +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..1f966b8b32c4 +index 0000000000000..1f966b8b32c45 --- /dev/null +++ b/drivers/hid/ipts/thread.h @@ -0,0 +1,59 @@ @@ -3856,9 +3893,62 @@ index 000000000000..1f966b8b32c4 + +#endif /* IPTS_THREAD_H */ -- -2.44.0 +2.45.1 + +From ee8823ff409dc4507cc2f7c8f8c474735b005938 Mon Sep 17 00:00:00 2001 +From: Jasmin Huber <jasmin@jasisonee.ch> +Date: Mon, 15 Apr 2024 10:22:55 +0200 +Subject: [PATCH] Inlude headers to avoid compiler warnings 6.8 kernels compile + with -Wmissing-prototypes. + +Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> +Patchset: ipts +--- + drivers/hid/ipts/eds1.c | 1 + + drivers/hid/ipts/eds2.c | 1 + + drivers/hid/ipts/receiver.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c +index ecbb3a8bdaf60..7b9f54388a9f6 100644 +--- a/drivers/hid/ipts/eds1.c ++++ b/drivers/hid/ipts/eds1.c +@@ -14,6 +14,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds1.h" + #include "spec-device.h" + + int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c +index 198dc65d78876..639940794615d 100644 +--- a/drivers/hid/ipts/eds2.c ++++ b/drivers/hid/ipts/eds2.c +@@ -15,6 +15,7 @@ + #include "context.h" + #include "control.h" + #include "desc.h" ++#include "eds2.h" + #include "spec-data.h" + + int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c +index ef66c3c9db807..977724c728c3e 100644 +--- a/drivers/hid/ipts/receiver.c ++++ b/drivers/hid/ipts/receiver.c +@@ -16,6 +16,7 @@ + #include "context.h" + #include "control.h" + #include "hid.h" ++#include "receiver.h" + #include "resources.h" + #include "spec-device.h" + #include "thread.h" +-- +2.45.1 -From 619b488e58367467f52d636b5182ff2134df68c0 Mon Sep 17 00:00:00 2001 +From 4b17942da35790b0e703a87267545f5a9f08e1cf Mon Sep 17 00:00:00 2001 From: Dorian Stoll <dorian.stoll@tmsp.io> Date: Sun, 11 Dec 2022 12:03:38 +0100 Subject: [PATCH] iommu: intel: Disable source id verification for ITHC @@ -3870,7 +3960,7 @@ Patchset: ithc 1 file changed, 16 insertions(+) diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index 566297bc87dd..a8cd8f12d593 100644 +index 566297bc87ddb..a8cd8f12d5937 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) @@ -3897,9 +3987,9 @@ index 566297bc87dd..a8cd8f12d593 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.44.0 +2.45.1 -From ee5106b4069dd150a323dce8bce7879d2b27ed0b Mon Sep 17 00:00:00 2001 +From 14baff1c79b6499868b48e6fb4ada851db35c941 Mon Sep 17 00:00:00 2001 From: quo <tuple@list.ru> Date: Sun, 11 Dec 2022 12:10:54 +0100 Subject: [PATCH] hid: Add support for Intel Touch Host Controller @@ -3932,7 +4022,7 @@ Patchset: ithc create mode 100644 drivers/hid/ithc/ithc.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index a263e49b2ae2..03f0f5af289a 100644 +index a263e49b2ae29..03f0f5af289a4 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1353,4 +1353,6 @@ source "drivers/hid/surface-hid/Kconfig" @@ -3943,7 +4033,7 @@ index a263e49b2ae2..03f0f5af289a 100644 + endif # HID_SUPPORT diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index f4bad1b8d813..d32c194400ae 100644 +index f4bad1b8d813f..d32c194400aea 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -172,3 +172,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ @@ -3953,7 +4043,7 @@ index f4bad1b8d813..d32c194400ae 100644 +obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..aea83f2ac07b +index 0000000000000..aea83f2ac07b4 --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -3965,7 +4055,7 @@ index 000000000000..aea83f2ac07b + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 0000000000000..ede7130236096 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -3983,7 +4073,7 @@ index 000000000000..ede713023609 + module will be called ithc. diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c new file mode 100644 -index 000000000000..1f1f1e33f2e5 +index 0000000000000..1f1f1e33f2e5a --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,130 @@ @@ -4119,7 +4209,7 @@ index 000000000000..1f1f1e33f2e5 + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..ffb8689b8a78 +index 0000000000000..ffb8689b8a780 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,373 @@ @@ -4498,7 +4588,7 @@ index 000000000000..ffb8689b8a78 + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..93652e4476bf +index 0000000000000..93652e4476bf8 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,69 @@ @@ -4573,7 +4663,7 @@ index 000000000000..93652e4476bf + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..87ed4aa70fda +index 0000000000000..87ed4aa70fda0 --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,728 @@ @@ -5307,7 +5397,7 @@ index 000000000000..87ed4aa70fda + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..e058721886e3 +index 0000000000000..e058721886e37 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,96 @@ @@ -5409,7 +5499,7 @@ index 000000000000..e058721886e3 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..d4007d9e2bac +index 0000000000000..d4007d9e2bacc --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,189 @@ @@ -5604,7 +5694,7 @@ index 000000000000..d4007d9e2bac + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..028e55a4ec53 +index 0000000000000..028e55a4ec53e --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,67 @@ @@ -5676,9 +5766,2801 @@ index 000000000000..028e55a4ec53 +void ithc_log_regs(struct ithc *ithc); + -- -2.44.0 +2.45.1 + +From 2537922b2f0c1d0002a2afe6d0fc79695add8e60 Mon Sep 17 00:00:00 2001 +From: quo <tuple@list.ru> +Date: Fri, 19 Apr 2024 22:11:09 +0200 +Subject: [PATCH] hid: ithc: Update from quo/ithc-linux + + - Added QuickSPI support for Surface Laptop Studio 2 + - Use Latency Tolerance Reporting instead of manual CPU latency adjustments + +Based on: https://github.com/quo/ithc-linux/commit/18afc6ffacd70b49fdee2eb1ab0a8acd159edb31 + +Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> +Patchset: ithc +--- + drivers/hid/ithc/Kbuild | 2 +- + drivers/hid/ithc/ithc-debug.c | 33 +- + drivers/hid/ithc/ithc-debug.h | 7 + + drivers/hid/ithc/ithc-dma.c | 125 ++----- + drivers/hid/ithc/ithc-dma.h | 24 +- + drivers/hid/ithc/ithc-hid.c | 207 +++++++++++ + drivers/hid/ithc/ithc-hid.h | 32 ++ + drivers/hid/ithc/ithc-legacy.c | 252 ++++++++++++++ + drivers/hid/ithc/ithc-legacy.h | 8 + + drivers/hid/ithc/ithc-main.c | 386 ++++----------------- + drivers/hid/ithc/ithc-quickspi.c | 578 +++++++++++++++++++++++++++++++ + drivers/hid/ithc/ithc-quickspi.h | 39 +++ + drivers/hid/ithc/ithc-regs.c | 72 +++- + drivers/hid/ithc/ithc-regs.h | 143 ++++---- + drivers/hid/ithc/ithc.h | 71 ++-- + 15 files changed, 1441 insertions(+), 538 deletions(-) + create mode 100644 drivers/hid/ithc/ithc-debug.h + create mode 100644 drivers/hid/ithc/ithc-hid.c + create mode 100644 drivers/hid/ithc/ithc-hid.h + create mode 100644 drivers/hid/ithc/ithc-legacy.c + create mode 100644 drivers/hid/ithc/ithc-legacy.h + create mode 100644 drivers/hid/ithc/ithc-quickspi.c + create mode 100644 drivers/hid/ithc/ithc-quickspi.h -From 973bf943acca4abdd932b5fdff032de0af07f96e Mon Sep 17 00:00:00 2001 +diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild +index aea83f2ac07b4..4937ba1312973 100644 +--- a/drivers/hid/ithc/Kbuild ++++ b/drivers/hid/ithc/Kbuild +@@ -1,6 +1,6 @@ + obj-$(CONFIG_HID_ITHC) := ithc.o + +-ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-debug.o ++ithc-objs := ithc-main.o ithc-regs.o ithc-dma.o ithc-hid.o ithc-legacy.o ithc-quickspi.o ithc-debug.o + + ccflags-y := -std=gnu11 -Wno-declaration-after-statement + +diff --git a/drivers/hid/ithc/ithc-debug.c b/drivers/hid/ithc/ithc-debug.c +index 1f1f1e33f2e5a..2d8c6afe99663 100644 +--- a/drivers/hid/ithc/ithc-debug.c ++++ b/drivers/hid/ithc/ithc-debug.c +@@ -85,10 +85,11 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + case 'd': // dma command: cmd len data... + // get report descriptor: d 7 8 0 0 + // enable multitouch: d 3 2 0x0105 +- if (n < 2 || a[1] > (n - 2) * 4) ++ if (n < 1) + return -EINVAL; +- pci_info(ithc->pci, "debug dma command %u with %u bytes of data\n", a[0], a[1]); +- if (ithc_dma_tx(ithc, a[0], a[1], a + 2)) ++ pci_info(ithc->pci, "debug dma command with %u bytes of data\n", n * 4); ++ struct ithc_data data = { .type = ITHC_DATA_RAW, .size = n * 4, .data = a }; ++ if (ithc_dma_tx(ithc, &data)) + pci_err(ithc->pci, "dma tx failed\n"); + break; + default: +@@ -98,6 +99,23 @@ static ssize_t ithc_debugfs_cmd_write(struct file *f, const char __user *buf, si + return len; + } + ++static struct dentry *dbg_dir; ++ ++void __init ithc_debug_init_module(void) ++{ ++ struct dentry *d = debugfs_create_dir(DEVNAME, NULL); ++ if (IS_ERR(d)) ++ pr_warn("failed to create debugfs dir (%li)\n", PTR_ERR(d)); ++ else ++ dbg_dir = d; ++} ++ ++void __exit ithc_debug_exit_module(void) ++{ ++ debugfs_remove_recursive(dbg_dir); ++ dbg_dir = NULL; ++} ++ + static const struct file_operations ithc_debugfops_cmd = { + .owner = THIS_MODULE, + .write = ithc_debugfs_cmd_write, +@@ -106,17 +124,18 @@ static const struct file_operations ithc_debugfops_cmd = { + static void ithc_debugfs_devres_release(struct device *dev, void *res) + { + struct dentry **dbgm = res; +- if (*dbgm) +- debugfs_remove_recursive(*dbgm); ++ debugfs_remove_recursive(*dbgm); + } + +-int ithc_debug_init(struct ithc *ithc) ++int ithc_debug_init_device(struct ithc *ithc) + { ++ if (!dbg_dir) ++ return -ENOENT; + struct dentry **dbgm = devres_alloc(ithc_debugfs_devres_release, sizeof(*dbgm), GFP_KERNEL); + if (!dbgm) + return -ENOMEM; + devres_add(&ithc->pci->dev, dbgm); +- struct dentry *dbg = debugfs_create_dir(DEVNAME, NULL); ++ struct dentry *dbg = debugfs_create_dir(pci_name(ithc->pci), dbg_dir); + if (IS_ERR(dbg)) + return PTR_ERR(dbg); + *dbgm = dbg; +diff --git a/drivers/hid/ithc/ithc-debug.h b/drivers/hid/ithc/ithc-debug.h +new file mode 100644 +index 0000000000000..38c53d916bdb5 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-debug.h +@@ -0,0 +1,7 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++void ithc_debug_init_module(void); ++void ithc_debug_exit_module(void); ++int ithc_debug_init_device(struct ithc *ithc); ++void ithc_log_regs(struct ithc *ithc); ++ +diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c +index ffb8689b8a780..bf4eab33062b0 100644 +--- a/drivers/hid/ithc/ithc-dma.c ++++ b/drivers/hid/ithc/ithc-dma.c +@@ -173,10 +173,9 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel) + mutex_init(&rx->mutex); + + // Allocate buffers. +- u32 buf_size = DEVCFG_DMA_RX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (buf_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_rx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating rx buffers: num = %u, size = %u, pages = %u\n", +- NUM_RX_BUF, buf_size, num_pages); ++ NUM_RX_BUF, ithc->max_rx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &rx->prds, NUM_RX_BUF, num_pages, DMA_FROM_DEVICE); + for (unsigned int i = 0; i < NUM_RX_BUF; i++) + CHECK_RET(ithc_dma_data_alloc, ithc, &rx->prds, &rx->bufs[i]); +@@ -214,10 +213,9 @@ int ithc_dma_tx_init(struct ithc *ithc) + mutex_init(&tx->mutex); + + // Allocate buffers. +- tx->max_size = DEVCFG_DMA_TX_SIZE(ithc->config.dma_buf_sizes); +- unsigned int num_pages = (tx->max_size + PAGE_SIZE - 1) / PAGE_SIZE; ++ unsigned int num_pages = (ithc->max_tx_size + PAGE_SIZE - 1) / PAGE_SIZE; + pci_dbg(ithc->pci, "allocating tx buffers: size = %u, pages = %u\n", +- tx->max_size, num_pages); ++ ithc->max_tx_size, num_pages); + CHECK_RET(ithc_dma_prd_alloc, ithc, &tx->prds, 1, num_pages, DMA_TO_DEVICE); + CHECK_RET(ithc_dma_data_alloc, ithc, &tx->prds, &tx->buf); + +@@ -230,71 +228,6 @@ int ithc_dma_tx_init(struct ithc *ithc) + return 0; + } + +-static int ithc_dma_rx_process_buf(struct ithc *ithc, struct ithc_dma_data_buffer *data, +- u8 channel, u8 buf) +-{ +- if (buf >= NUM_RX_BUF) { +- pci_err(ithc->pci, "invalid dma ringbuffer index\n"); +- return -EINVAL; +- } +- u32 len = data->data_size; +- struct ithc_dma_rx_header *hdr = data->addr; +- u8 *hiddata = (void *)(hdr + 1); +- if (len >= sizeof(*hdr) && hdr->code == DMA_RX_CODE_RESET) { +- // The THC sends a reset request when we need to reinitialize the device. +- // This usually only happens if we send an invalid command or put the device +- // in a bad state. +- CHECK(ithc_reset, ithc); +- } else if (len < sizeof(*hdr) || len != sizeof(*hdr) + hdr->data_size) { +- if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // When the CPU enters a low power state during DMA, we can get truncated +- // messages. For Surface devices, this will typically be a single touch +- // report that is only 1 byte, or a multitouch report that is 257 bytes. +- // See also ithc_set_active(). +- } else { +- pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u, code %u, data size %u\n", +- channel, buf, len, hdr->code, hdr->data_size); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- } else if (hdr->code == DMA_RX_CODE_REPORT_DESCRIPTOR && hdr->data_size > 8) { +- // Response to a 'get report descriptor' request. +- // The actual descriptor is preceded by 8 nul bytes. +- CHECK(hid_parse_report, ithc->hid, hiddata + 8, hdr->data_size - 8); +- WRITE_ONCE(ithc->hid_parse_done, true); +- wake_up(&ithc->wait_hid_parse); +- } else if (hdr->code == DMA_RX_CODE_INPUT_REPORT) { +- // Standard HID input report containing touch data. +- CHECK(hid_input_report, ithc->hid, HID_INPUT_REPORT, hiddata, hdr->data_size, 1); +- } else if (hdr->code == DMA_RX_CODE_FEATURE_REPORT) { +- // Response to a 'get feature' request. +- bool done = false; +- mutex_lock(&ithc->hid_get_feature_mutex); +- if (ithc->hid_get_feature_buf) { +- if (hdr->data_size < ithc->hid_get_feature_size) +- ithc->hid_get_feature_size = hdr->data_size; +- memcpy(ithc->hid_get_feature_buf, hiddata, ithc->hid_get_feature_size); +- ithc->hid_get_feature_buf = NULL; +- done = true; +- } +- mutex_unlock(&ithc->hid_get_feature_mutex); +- if (done) { +- wake_up(&ithc->wait_hid_get_feature); +- } else { +- // Received data without a matching request, or the request already +- // timed out. (XXX What's the correct thing to do here?) +- CHECK(hid_input_report, ithc->hid, HID_FEATURE_REPORT, +- hiddata, hdr->data_size, 1); +- } +- } else { +- pci_dbg(ithc->pci, "unhandled dma rx data! channel %u, buffer %u, size %u, code %u\n", +- channel, buf, len, hdr->code); +- print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, +- hdr, min(len, 0x400u), 0); +- } +- return 0; +-} +- + static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + { + // Process all filled RX buffers from the ringbuffer. +@@ -316,7 +249,16 @@ static int ithc_dma_rx_unlocked(struct ithc *ithc, u8 channel) + rx->num_received = ++n; + + // process data +- CHECK(ithc_dma_rx_process_buf, ithc, b, channel, tail); ++ struct ithc_data d; ++ if ((ithc->use_quickspi ? ithc_quickspi_decode_rx : ithc_legacy_decode_rx) ++ (ithc, b->addr, b->data_size, &d) < 0) { ++ pci_err(ithc->pci, "invalid dma rx data! channel %u, buffer %u, size %u: %*ph\n", ++ channel, tail, b->data_size, min((int)b->data_size, 64), b->addr); ++ print_hex_dump_debug(DEVNAME " data: ", DUMP_PREFIX_OFFSET, 32, 1, ++ b->addr, min(b->data_size, 0x400u), 0); ++ } else { ++ ithc_hid_process_data(ithc, &d); ++ } + + // give the buffer back to the device + CHECK_RET(ithc_dma_data_buffer_put, ithc, &rx->prds, b, tail); +@@ -331,31 +273,28 @@ int ithc_dma_rx(struct ithc *ithc, u8 channel) + return ret; + } + +-static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++static int ithc_dma_tx_unlocked(struct ithc *ithc, const struct ithc_data *data) + { +- ithc_set_active(ithc, 100 * USEC_PER_MSEC); +- + // Send a single TX buffer to the THC. +- pci_dbg(ithc->pci, "dma tx command %u, size %u\n", cmdcode, datasize); +- struct ithc_dma_tx_header *hdr; +- // Data must be padded to next 4-byte boundary. +- u8 padding = datasize & 3 ? 4 - (datasize & 3) : 0; +- unsigned int fullsize = sizeof(*hdr) + datasize + padding; +- if (fullsize > ithc->dma_tx.max_size || fullsize > PAGE_SIZE) +- return -EINVAL; ++ pci_dbg(ithc->pci, "dma tx data type %u, size %u\n", data->type, data->size); + CHECK_RET(ithc_dma_data_buffer_get, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); + + // Fill the TX buffer with header and data. +- ithc->dma_tx.buf.data_size = fullsize; +- hdr = ithc->dma_tx.buf.addr; +- hdr->code = cmdcode; +- hdr->data_size = datasize; +- u8 *dest = (void *)(hdr + 1); +- memcpy(dest, data, datasize); +- dest += datasize; +- for (u8 p = 0; p < padding; p++) +- *dest++ = 0; ++ ssize_t sz; ++ if (data->type == ITHC_DATA_RAW) { ++ sz = min(data->size, ithc->max_tx_size); ++ memcpy(ithc->dma_tx.buf.addr, data->data, sz); ++ } else { ++ sz = (ithc->use_quickspi ? ithc_quickspi_encode_tx : ithc_legacy_encode_tx) ++ (ithc, data, ithc->dma_tx.buf.addr, ithc->max_tx_size); ++ } ++ ithc->dma_tx.buf.data_size = sz < 0 ? 0 : sz; + CHECK_RET(ithc_dma_data_buffer_put, ithc, &ithc->dma_tx.prds, &ithc->dma_tx.buf, 0); ++ if (sz < 0) { ++ pci_err(ithc->pci, "failed to encode tx data type %i, size %u, error %i\n", ++ data->type, data->size, (int)sz); ++ return -EINVAL; ++ } + + // Let the THC process the buffer. + bitsb_set(&ithc->regs->dma_tx.control, DMA_TX_CONTROL_SEND); +@@ -363,10 +302,10 @@ static int ithc_dma_tx_unlocked(struct ithc *ithc, u32 cmdcode, u32 datasize, vo + writel(DMA_TX_STATUS_DONE, &ithc->regs->dma_tx.status); + return 0; + } +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *data) ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data) + { + mutex_lock(&ithc->dma_tx.mutex); +- int ret = ithc_dma_tx_unlocked(ithc, cmdcode, datasize, data); ++ int ret = ithc_dma_tx_unlocked(ithc, data); + mutex_unlock(&ithc->dma_tx.mutex); + return ret; + } +diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h +index 93652e4476bf8..1749a5819b3e7 100644 +--- a/drivers/hid/ithc/ithc-dma.h ++++ b/drivers/hid/ithc/ithc-dma.h +@@ -11,27 +11,6 @@ struct ithc_phys_region_desc { + u32 unused; + }; + +-#define DMA_RX_CODE_INPUT_REPORT 3 +-#define DMA_RX_CODE_FEATURE_REPORT 4 +-#define DMA_RX_CODE_REPORT_DESCRIPTOR 5 +-#define DMA_RX_CODE_RESET 7 +- +-struct ithc_dma_rx_header { +- u32 code; +- u32 data_size; +- u32 _unknown[14]; +-}; +- +-#define DMA_TX_CODE_SET_FEATURE 3 +-#define DMA_TX_CODE_GET_FEATURE 4 +-#define DMA_TX_CODE_OUTPUT_REPORT 5 +-#define DMA_TX_CODE_GET_REPORT_DESCRIPTOR 7 +- +-struct ithc_dma_tx_header { +- u32 code; +- u32 data_size; +-}; +- + struct ithc_dma_prd_buffer { + void *addr; + dma_addr_t dma_addr; +@@ -49,7 +28,6 @@ struct ithc_dma_data_buffer { + + struct ithc_dma_tx { + struct mutex mutex; +- u32 max_size; + struct ithc_dma_prd_buffer prds; + struct ithc_dma_data_buffer buf; + }; +@@ -65,5 +43,5 @@ int ithc_dma_rx_init(struct ithc *ithc, u8 channel); + void ithc_dma_rx_enable(struct ithc *ithc, u8 channel); + int ithc_dma_tx_init(struct ithc *ithc); + int ithc_dma_rx(struct ithc *ithc, u8 channel); +-int ithc_dma_tx(struct ithc *ithc, u32 cmdcode, u32 datasize, void *cmddata); ++int ithc_dma_tx(struct ithc *ithc, const struct ithc_data *data); + +diff --git a/drivers/hid/ithc/ithc-hid.c b/drivers/hid/ithc/ithc-hid.c +new file mode 100644 +index 0000000000000..065646ab499ef +--- /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) ++{ ++ struct { ++ u32 code; ++ u32 data_size; ++ } *hdr = dest; ++ ++ size_t src_size = src->size; ++ const void *src_data = src->data; ++ const u64 get_report_desc_data = 0; ++ u32 code; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ code = TX_CODE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ code = TX_CODE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ code = TX_CODE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ code = TX_CODE_GET_REPORT_DESCRIPTOR; ++ src_size = sizeof(get_report_desc_data); ++ src_data = &get_report_desc_data; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->code = code; ++ hdr->data_size = src_size; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-legacy.h b/drivers/hid/ithc/ithc-legacy.h +new file mode 100644 +index 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); ++ ++ CHECK(ithc_debug_init_device, ithc); + +- CHECK(ithc_debug_init, ithc); ++ ithc_set_ltr_idle(ithc); + + pci_dbg(pci, "started\n"); + return 0; +@@ -710,17 +451,20 @@ static struct pci_driver ithc_driver = { + .thaw = ithc_thaw, + .restore = ithc_restore, + }, ++ .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, + //.dev_groups = ithc_attribute_groups, // could use this (since 5.14), however the attributes won't have valid values until config has been read anyway + }; + + static int __init ithc_init(void) + { ++ ithc_debug_init_module(); + return pci_register_driver(&ithc_driver); + } + + static void __exit ithc_exit(void) + { + pci_unregister_driver(&ithc_driver); ++ ithc_debug_exit_module(); + } + + module_init(ithc_init); +diff --git a/drivers/hid/ithc/ithc-quickspi.c b/drivers/hid/ithc/ithc-quickspi.c +new file mode 100644 +index 0000000000000..760e55ead0788 +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.c +@@ -0,0 +1,578 @@ ++// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause ++ ++// Some public THC/QuickSPI documentation can be found in: ++// - Intel Firmware Support Package repo: https://github.com/intel/FSP ++// - HID over SPI (HIDSPI) spec: https://www.microsoft.com/en-us/download/details.aspx?id=103325 ++ ++#include "ithc.h" ++ ++static const guid_t guid_hidspi = ++ GUID_INIT(0x6e2ac436, 0x0fcf, 0x41af, 0xa2, 0x65, 0xb3, 0x2a, 0x22, 0x0d, 0xcf, 0xab); ++static const guid_t guid_thc_quickspi = ++ GUID_INIT(0x300d35b7, 0xac20, 0x413e, 0x8e, 0x9c, 0x92, 0xe4, 0xda, 0xfd, 0x0a, 0xfe); ++static const guid_t guid_thc_ltr = ++ GUID_INIT(0x84005682, 0x5b71, 0x41a4, 0x8d, 0x66, 0x81, 0x30, 0xf7, 0x87, 0xa1, 0x38); ++ ++// TODO The HIDSPI spec says revision should be 3. Should we try both? ++#define DSM_REV 2 ++ ++struct hidspi_header { ++ u8 type; ++ u16 len; ++ u8 id; ++} __packed; ++static_assert(sizeof(struct hidspi_header) == 4); ++ ++#define HIDSPI_INPUT_TYPE_DATA 1 ++#define HIDSPI_INPUT_TYPE_RESET_RESPONSE 3 ++#define HIDSPI_INPUT_TYPE_COMMAND_RESPONSE 4 ++#define HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE 5 ++#define HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR 7 ++#define HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR 8 ++#define HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE 9 ++#define HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE 10 ++#define HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE 11 ++ ++#define HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST 1 ++#define HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST 2 ++#define HIDSPI_OUTPUT_TYPE_SET_FEATURE 3 ++#define HIDSPI_OUTPUT_TYPE_GET_FEATURE 4 ++#define HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT 5 ++#define HIDSPI_OUTPUT_TYPE_INPUT_REPORT_REQUEST 6 ++#define HIDSPI_OUTPUT_TYPE_COMMAND 7 ++ ++struct hidspi_device_descriptor { ++ u16 wDeviceDescLength; ++ u16 bcdVersion; ++ u16 wReportDescLength; ++ u16 wMaxInputLength; ++ u16 wMaxOutputLength; ++ u16 wMaxFragmentLength; ++ u16 wVendorID; ++ u16 wProductID; ++ u16 wVersionID; ++ u16 wFlags; ++ u32 dwReserved; ++}; ++static_assert(sizeof(struct hidspi_device_descriptor) == 24); ++ ++static int read_acpi_u32(struct ithc *ithc, const guid_t *guid, u32 func, u32 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_INTEGER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of integer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%08x\n", guid, func, (u32)o->integer.value); ++ *dest = (u32)o->integer.value; ++ ACPI_FREE(o); ++ return 1; ++} ++ ++static int read_acpi_buf(struct ithc *ithc, const guid_t *guid, u32 func, size_t len, u8 *dest) ++{ ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ union acpi_object *o = acpi_evaluate_dsm(handle, guid, DSM_REV, func, NULL); ++ if (!o) ++ return 0; ++ if (o->type != ACPI_TYPE_BUFFER) { ++ pci_err(ithc->pci, "DSM %pUl %u returned type %i instead of buffer\n", ++ guid, func, o->type); ++ ACPI_FREE(o); ++ return -1; ++ } ++ if (o->buffer.length != len) { ++ pci_err(ithc->pci, "DSM %pUl %u returned len %u instead of %zu\n", ++ guid, func, o->buffer.length, len); ++ ACPI_FREE(o); ++ return -1; ++ } ++ memcpy(dest, o->buffer.pointer, len); ++ pci_dbg(ithc->pci, "DSM %pUl %u = 0x%02x\n", guid, func, dest[0]); ++ ACPI_FREE(o); ++ return 1; ++} ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg) ++{ ++ int r; ++ acpi_handle handle = ACPI_HANDLE(&ithc->pci->dev); ++ ++ cfg->has_config = acpi_check_dsm(handle, &guid_hidspi, DSM_REV, BIT(0)); ++ if (!cfg->has_config) ++ return 0; ++ ++ // HIDSPI settings ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 1, &cfg->input_report_header_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_header_address = r > 0; ++ if (r > 0 && cfg->input_report_header_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report header address 0x%x\n", ++ cfg->input_report_header_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 2, &cfg->input_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_input_report_body_address = r > 0; ++ if (r > 0 && cfg->input_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid input report body address 0x%x\n", ++ cfg->input_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_hidspi, 3, &cfg->output_report_body_address); ++ if (r < 0) ++ return r; ++ cfg->has_output_report_body_address = r > 0; ++ if (r > 0 && cfg->output_report_body_address > 0xffffff) { ++ pci_err(ithc->pci, "Invalid output report body address 0x%x\n", ++ cfg->output_report_body_address); ++ return -1; ++ } ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 4, sizeof(cfg->read_opcode), &cfg->read_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_read_opcode = r > 0; ++ ++ r = read_acpi_buf(ithc, &guid_hidspi, 5, sizeof(cfg->write_opcode), &cfg->write_opcode); ++ if (r < 0) ++ return r; ++ cfg->has_write_opcode = r > 0; ++ ++ u32 flags; ++ r = read_acpi_u32(ithc, &guid_hidspi, 6, &flags); ++ if (r < 0) ++ return r; ++ cfg->has_read_mode = cfg->has_write_mode = r > 0; ++ if (r > 0) { ++ cfg->read_mode = (flags >> 14) & 3; ++ cfg->write_mode = flags & BIT(13) ? cfg->read_mode : SPI_MODE_SINGLE; ++ } ++ ++ // Quick SPI settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 1, &cfg->spi_frequency); ++ if (r < 0) ++ return r; ++ cfg->has_spi_frequency = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 2, &cfg->limit_packet_size); ++ if (r < 0) ++ return r; ++ cfg->has_limit_packet_size = r > 0; ++ ++ r = read_acpi_u32(ithc, &guid_thc_quickspi, 3, &cfg->tx_delay); ++ if (r < 0) ++ return r; ++ cfg->has_tx_delay = r > 0; ++ if (r > 0) ++ cfg->tx_delay &= 0xffff; ++ ++ // LTR settings ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 1, &cfg->active_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_active_ltr = r > 0; ++ if (r > 0 && (!cfg->active_ltr || cfg->active_ltr > 0x3ff)) { ++ if (cfg->active_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid active LTR value 0x%x\n", ++ cfg->active_ltr); ++ cfg->active_ltr = 500; ++ } ++ ++ r = read_acpi_u32(ithc, &guid_thc_ltr, 2, &cfg->idle_ltr); ++ if (r < 0) ++ return r; ++ cfg->has_idle_ltr = r > 0; ++ if (r > 0 && (!cfg->idle_ltr || cfg->idle_ltr > 0x3ff)) { ++ if (cfg->idle_ltr != 0xffffffff) ++ pci_warn(ithc->pci, "Ignoring invalid idle LTR value 0x%x\n", ++ cfg->idle_ltr); ++ cfg->idle_ltr = 500; ++ if (cfg->has_active_ltr && cfg->active_ltr > cfg->idle_ltr) ++ cfg->idle_ltr = cfg->active_ltr; ++ } ++ ++ return 0; ++} ++ ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ if (!cfg->has_config) { ++ pci_info(ithc->pci, "No ACPI config"); ++ return; ++ } ++ ++ char input_report_header_address[16] = "-"; ++ if (cfg->has_input_report_header_address) ++ sprintf(input_report_header_address, "0x%x", cfg->input_report_header_address); ++ char input_report_body_address[16] = "-"; ++ if (cfg->has_input_report_body_address) ++ sprintf(input_report_body_address, "0x%x", cfg->input_report_body_address); ++ char output_report_body_address[16] = "-"; ++ if (cfg->has_output_report_body_address) ++ sprintf(output_report_body_address, "0x%x", cfg->output_report_body_address); ++ char read_opcode[16] = "-"; ++ if (cfg->has_read_opcode) ++ sprintf(read_opcode, "0x%02x", cfg->read_opcode); ++ char write_opcode[16] = "-"; ++ if (cfg->has_write_opcode) ++ sprintf(write_opcode, "0x%02x", cfg->write_opcode); ++ char read_mode[16] = "-"; ++ if (cfg->has_read_mode) ++ sprintf(read_mode, "%i", cfg->read_mode); ++ char write_mode[16] = "-"; ++ if (cfg->has_write_mode) ++ sprintf(write_mode, "%i", cfg->write_mode); ++ char spi_frequency[16] = "-"; ++ if (cfg->has_spi_frequency) ++ sprintf(spi_frequency, "%u", cfg->spi_frequency); ++ char limit_packet_size[16] = "-"; ++ if (cfg->has_limit_packet_size) ++ sprintf(limit_packet_size, "%u", cfg->limit_packet_size); ++ char tx_delay[16] = "-"; ++ if (cfg->has_tx_delay) ++ sprintf(tx_delay, "%u", cfg->tx_delay); ++ char active_ltr[16] = "-"; ++ if (cfg->has_active_ltr) ++ sprintf(active_ltr, "%u", cfg->active_ltr); ++ char idle_ltr[16] = "-"; ++ if (cfg->has_idle_ltr) ++ sprintf(idle_ltr, "%u", cfg->idle_ltr); ++ ++ pci_info(ithc->pci, "ACPI config: InputHeaderAddr=%s InputBodyAddr=%s OutputBodyAddr=%s ReadOpcode=%s WriteOpcode=%s ReadMode=%s WriteMode=%s Frequency=%s LimitPacketSize=%s TxDelay=%s ActiveLTR=%s IdleLTR=%s\n", ++ input_report_header_address, input_report_body_address, output_report_body_address, ++ read_opcode, write_opcode, read_mode, write_mode, ++ spi_frequency, limit_packet_size, tx_delay, active_ltr, idle_ltr); ++} ++ ++static int ithc_quickspi_init_regs(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing QuickSPI registers\n"); ++ ++ // SPI frequency and mode ++ if (!cfg->has_spi_frequency || !cfg->spi_frequency) { ++ pci_err(ithc->pci, "Missing SPI frequency in configuration\n"); ++ return -EINVAL; ++ } ++ unsigned int clkdiv = DIV_ROUND_UP(SPI_CLK_FREQ_BASE, cfg->spi_frequency); ++ bool clkdiv8 = clkdiv > 7; ++ if (clkdiv8) ++ clkdiv = min(7u, DIV_ROUND_UP(clkdiv, 8u)); ++ if (!clkdiv) ++ clkdiv = 1; ++ CHECK_RET(ithc_set_spi_config, ithc, clkdiv, clkdiv8, ++ cfg->has_read_mode ? cfg->read_mode : SPI_MODE_SINGLE, ++ cfg->has_write_mode ? cfg->write_mode : SPI_MODE_SINGLE); ++ ++ // SPI addresses and opcodes ++ if (cfg->has_input_report_header_address) ++ writel(cfg->input_report_header_address, &ithc->regs->spi_header_addr); ++ if (cfg->has_input_report_body_address) ++ writel(cfg->input_report_body_address, &ithc->regs->dma_rx[0].spi_addr); ++ if (cfg->has_output_report_body_address) ++ writel(cfg->output_report_body_address, &ithc->regs->dma_tx.spi_addr); ++ ++ if (cfg->has_read_opcode) { ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_single); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_dual); ++ writeb(cfg->read_opcode, &ithc->regs->read_opcode_quad); ++ } ++ if (cfg->has_write_opcode) { ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_single); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_dual); ++ writeb(cfg->write_opcode, &ithc->regs->write_opcode_quad); ++ } ++ ithc_log_regs(ithc); ++ ++ // The rest... ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_0(0xff) | QUICKSPI_CONFIG1_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(0xff) | QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), ++ QUICKSPI_CONFIG1_UNKNOWN_0(4) | QUICKSPI_CONFIG1_UNKNOWN_5(4) | ++ QUICKSPI_CONFIG1_UNKNOWN_10(22) | QUICKSPI_CONFIG1_UNKNOWN_16(2)); ++ ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_0(0xff) | QUICKSPI_CONFIG2_UNKNOWN_5(0xff) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(0xff), ++ QUICKSPI_CONFIG2_UNKNOWN_0(8) | QUICKSPI_CONFIG2_UNKNOWN_5(14) | ++ QUICKSPI_CONFIG2_UNKNOWN_12(2)); ++ ++ u32 pktsize = cfg->has_limit_packet_size && cfg->limit_packet_size == 1 ? 4 : 0x80; ++ bitsl(&ithc->regs->spi_config, ++ SPI_CONFIG_READ_PACKET_SIZE(0xfff) | SPI_CONFIG_WRITE_PACKET_SIZE(0xfff), ++ SPI_CONFIG_READ_PACKET_SIZE(pktsize) | SPI_CONFIG_WRITE_PACKET_SIZE(pktsize)); ++ ++ bitsl_set(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_UNKNOWN_16 | QUICKSPI_CONFIG2_UNKNOWN_17); ++ bitsl(&ithc->regs->quickspi_config2, ++ QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT | ++ QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE, 0); ++ ++ return 0; ++} ++ ++static int wait_for_report(struct ithc *ithc) ++{ ++ CHECK_RET(waitl, ithc, &ithc->regs->dma_rx[0].status, ++ DMA_RX_STATUS_READY, DMA_RX_STATUS_READY); ++ writel(DMA_RX_STATUS_READY, &ithc->regs->dma_rx[0].status); ++ ++ u32 h = readl(&ithc->regs->input_header); ++ ithc_log_regs(ithc); ++ if (INPUT_HEADER_SYNC(h) != INPUT_HEADER_SYNC_VALUE ++ || INPUT_HEADER_VERSION(h) != INPUT_HEADER_VERSION_VALUE) { ++ pci_err(ithc->pci, "invalid input report frame header 0x%08x\n", h); ++ return -ENODATA; ++ } ++ return INPUT_HEADER_REPORT_LENGTH(h) * 4; ++} ++ ++static int ithc_quickspi_init_hidspi(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ pci_dbg(ithc->pci, "initializing HIDSPI\n"); ++ ++ // HIDSPI initialization sequence: ++ // "1. The host shall invoke the ACPI reset method to clear the device state." ++ acpi_status s = acpi_evaluate_object(ACPI_HANDLE(&ithc->pci->dev), "_RST", NULL, NULL); ++ if (ACPI_FAILURE(s)) { ++ pci_err(ithc->pci, "ACPI reset failed\n"); ++ return -EIO; ++ } ++ ++ bitsl(&ithc->regs->control_bits, CONTROL_QUIESCE, 0); ++ ++ // "2. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing a device reset response." ++ int size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(struct hidspi_header)) { ++ pci_err(ithc->pci, "SPI data size too small for reset response (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "3. The host shall read the reset response from the device at the Input Report addresses ++ // specified in ACPI." ++ u32 in_addr = cfg->has_input_report_body_address ? cfg->input_report_body_address : 0x1000; ++ struct { ++ struct hidspi_header header; ++ union { ++ struct hidspi_device_descriptor device_desc; ++ u32 data[16]; ++ }; ++ } resp = { 0 }; ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for reset response too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_RESET_RESPONSE) { ++ pci_err(ithc->pci, "received type %i instead of reset response\n", resp.header.type); ++ return -ENOMSG; ++ } ++ ++ // "4. The host shall then write an Output Report to the device at the Output Report Address ++ // specified in ACPI, requesting the Device Descriptor from the device." ++ u32 out_addr = cfg->has_output_report_body_address ? cfg->output_report_body_address : 0x1000; ++ struct hidspi_header req = { .type = HIDSPI_OUTPUT_TYPE_DEVICE_DESCRIPTOR_REQUEST }; ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_WRITE, out_addr, sizeof(req), &req); ++ ++ // "5. Within 1 second, the device shall signal an interrupt and make available to the host ++ // an input report containing the Device Descriptor." ++ size = wait_for_report(ithc); ++ if (size < 0) ++ return size; ++ if (size < sizeof(resp.header) + sizeof(resp.device_desc)) { ++ pci_err(ithc->pci, "SPI data size too small for device descriptor (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ ++ // "6. The host shall read the Device Descriptor from the Input Report addresses specified ++ // in ACPI." ++ if (size > sizeof(resp)) { ++ pci_err(ithc->pci, "SPI data size for device descriptor too big (%u)\n", size); ++ return -EMSGSIZE; ++ } ++ memset(&resp, 0, sizeof(resp)); ++ CHECK_RET(ithc_spi_command, ithc, SPI_CMD_CODE_READ, in_addr, size, &resp); ++ if (resp.header.type != HIDSPI_INPUT_TYPE_DEVICE_DESCRIPTOR) { ++ pci_err(ithc->pci, "received type %i instead of device descriptor\n", ++ resp.header.type); ++ return -ENOMSG; ++ } ++ struct hidspi_device_descriptor *d = &resp.device_desc; ++ if (resp.header.len < sizeof(*d)) { ++ pci_err(ithc->pci, "response too small for device descriptor (%u)\n", ++ resp.header.len); ++ return -EMSGSIZE; ++ } ++ if (d->wDeviceDescLength != sizeof(*d)) { ++ pci_err(ithc->pci, "invalid device descriptor length (%u)\n", ++ d->wDeviceDescLength); ++ return -EMSGSIZE; ++ } ++ ++ pci_info(ithc->pci, "Device descriptor: bcdVersion=0x%04x wReportDescLength=%u wMaxInputLength=%u wMaxOutputLength=%u wMaxFragmentLength=%u wVendorID=0x%04x wProductID=0x%04x wVersionID=0x%04x wFlags=0x%04x dwReserved=0x%08x\n", ++ d->bcdVersion, d->wReportDescLength, ++ d->wMaxInputLength, d->wMaxOutputLength, d->wMaxFragmentLength, ++ d->wVendorID, d->wProductID, d->wVersionID, ++ d->wFlags, d->dwReserved); ++ ++ ithc->vendor_id = d->wVendorID; ++ ithc->product_id = d->wProductID; ++ ithc->product_rev = d->wVersionID; ++ ithc->max_rx_size = max_t(u32, d->wMaxInputLength, ++ d->wReportDescLength + sizeof(struct hidspi_header)); ++ ithc->max_tx_size = d->wMaxOutputLength; ++ ithc->have_config = true; ++ ++ // "7. The device and host shall then enter their "Ready" states - where the device may ++ // begin sending Input Reports, and the device shall be prepared for Output Reports from ++ // the host." ++ ++ return 0; ++} ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg) ++{ ++ bitsl_set(&ithc->regs->control_bits, CONTROL_QUIESCE); ++ CHECK_RET(waitl, ithc, &ithc->regs->control_bits, CONTROL_IS_QUIESCED, CONTROL_IS_QUIESCED); ++ ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_regs, ithc, cfg); ++ ithc_log_regs(ithc); ++ CHECK_RET(ithc_quickspi_init_hidspi, ithc, cfg); ++ ithc_log_regs(ithc); ++ ++ // This value is set to 2 in ithc_quickspi_init_regs(). It needs to be set to 1 here, ++ // otherwise DMA will not work. Maybe selects between DMA and PIO mode? ++ bitsl(&ithc->regs->quickspi_config1, ++ QUICKSPI_CONFIG1_UNKNOWN_16(0xffff), QUICKSPI_CONFIG1_UNKNOWN_16(1)); ++ ++ // TODO Do we need to set any of the following bits here? ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_4); ++ //bitsb_set(&ithc->regs->dma_rx[0].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsb_set(&ithc->regs->dma_rx[1].control2, DMA_RX_CONTROL2_UNKNOWN_5); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_3); ++ //bitsl_set(&ithc->regs->dma_rx[0].init_unknown, INIT_UNKNOWN_31); ++ ++ ithc_log_regs(ithc); ++ ++ return 0; ++} ++ ++void ithc_quickspi_exit(struct ithc *ithc) ++{ ++ // TODO Should we send HIDSPI 'power off' command? ++ //struct hidspi_header h = { .type = HIDSPI_OUTPUT_TYPE_COMMAND, .id = 3, }; ++ //struct ithc_data d = { .type = ITHC_DATA_RAW, .data = &h, .size = sizeof(h) }; ++ //CHECK(ithc_dma_tx, ithc, &d); // or ithc_spi_command() ++} ++ ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest) ++{ ++ const struct hidspi_header *hdr = src; ++ ++ if (len < sizeof(*hdr)) ++ return -ENODATA; ++ // TODO Do we need to handle HIDSPI packet fragmentation? ++ if (len < sizeof(*hdr) + hdr->len) ++ return -EMSGSIZE; ++ if (len > round_up(sizeof(*hdr) + hdr->len, 4)) ++ return -EMSGSIZE; ++ ++ switch (hdr->type) { ++ case HIDSPI_INPUT_TYPE_RESET_RESPONSE: ++ // TODO "When the device detects an error condition, it may interrupt and make ++ // available to the host an Input Report containing an unsolicited Reset Response. ++ // After receiving an unsolicited Reset Response, the host shall initiate the ++ // request procedure from step (4) in the [HIDSPI initialization] process." ++ dest->type = ITHC_DATA_ERROR; ++ return 0; ++ case HIDSPI_INPUT_TYPE_REPORT_DESCRIPTOR: ++ dest->type = ITHC_DATA_REPORT_DESCRIPTOR; ++ dest->data = hdr + 1; ++ dest->size = hdr->len; ++ return 0; ++ case HIDSPI_INPUT_TYPE_DATA: ++ case HIDSPI_INPUT_TYPE_GET_INPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_INPUT_REPORT; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_GET_FEATURE_RESPONSE: ++ dest->type = ITHC_DATA_GET_FEATURE; ++ dest->data = &hdr->id; ++ dest->size = hdr->len + 1; ++ return 0; ++ case HIDSPI_INPUT_TYPE_SET_FEATURE_RESPONSE: ++ case HIDSPI_INPUT_TYPE_OUTPUT_REPORT_RESPONSE: ++ dest->type = ITHC_DATA_IGNORE; ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen) ++{ ++ struct hidspi_header *hdr = dest; ++ ++ size_t src_size = src->size; ++ const u8 *src_data = src->data; ++ u8 type; ++ ++ switch (src->type) { ++ case ITHC_DATA_SET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_SET_FEATURE; ++ break; ++ case ITHC_DATA_GET_FEATURE: ++ type = HIDSPI_OUTPUT_TYPE_GET_FEATURE; ++ break; ++ case ITHC_DATA_OUTPUT_REPORT: ++ type = HIDSPI_OUTPUT_TYPE_OUTPUT_REPORT; ++ break; ++ case ITHC_DATA_REPORT_DESCRIPTOR: ++ type = HIDSPI_OUTPUT_TYPE_REPORT_DESCRIPTOR_REQUEST; ++ src_size = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ u8 id = 0; ++ if (src_size) { ++ id = *src_data++; ++ src_size--; ++ } ++ ++ // Data must be padded to next 4-byte boundary. ++ size_t padded = round_up(src_size, 4); ++ if (sizeof(*hdr) + padded > maxlen) ++ return -EOVERFLOW; ++ ++ // Fill the TX buffer with header and data. ++ hdr->type = type; ++ hdr->len = (u16)src_size; ++ hdr->id = id; ++ memcpy_and_pad(hdr + 1, padded, src_data, src_size, 0); ++ ++ return sizeof(*hdr) + padded; ++} ++ +diff --git a/drivers/hid/ithc/ithc-quickspi.h b/drivers/hid/ithc/ithc-quickspi.h +new file mode 100644 +index 0000000000000..74d882f6b2f0a +--- /dev/null ++++ b/drivers/hid/ithc/ithc-quickspi.h +@@ -0,0 +1,39 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ ++ ++struct ithc_acpi_config { ++ bool has_config: 1; ++ bool has_input_report_header_address: 1; ++ bool has_input_report_body_address: 1; ++ bool has_output_report_body_address: 1; ++ bool has_read_opcode: 1; ++ bool has_write_opcode: 1; ++ bool has_read_mode: 1; ++ bool has_write_mode: 1; ++ bool has_spi_frequency: 1; ++ bool has_limit_packet_size: 1; ++ bool has_tx_delay: 1; ++ bool has_active_ltr: 1; ++ bool has_idle_ltr: 1; ++ u32 input_report_header_address; ++ u32 input_report_body_address; ++ u32 output_report_body_address; ++ u8 read_opcode; ++ u8 write_opcode; ++ u8 read_mode; ++ u8 write_mode; ++ u32 spi_frequency; ++ u32 limit_packet_size; ++ u32 tx_delay; // us/10 // TODO use? ++ u32 active_ltr; // ns/1024 ++ u32 idle_ltr; // ns/1024 ++}; ++ ++int ithc_read_acpi_config(struct ithc *ithc, struct ithc_acpi_config *cfg); ++void ithc_print_acpi_config(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++ ++int ithc_quickspi_init(struct ithc *ithc, const struct ithc_acpi_config *cfg); ++void ithc_quickspi_exit(struct ithc *ithc); ++int ithc_quickspi_decode_rx(struct ithc *ithc, const void *src, size_t len, struct ithc_data *dest); ++ssize_t ithc_quickspi_encode_tx(struct ithc *ithc, const struct ithc_data *src, void *dest, ++ size_t maxlen); ++ +diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c +index e058721886e37..c0f13506af205 100644 +--- a/drivers/hid/ithc/ithc-regs.c ++++ b/drivers/hid/ithc/ithc-regs.c +@@ -22,46 +22,104 @@ void bitsb(__iomem u8 *reg, u8 mask, u8 val) + + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + u32 x; + if (readl_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%08x val 0x%08x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val) + { ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + u8 x; + if (readb_poll_timeout(reg, x, (x & mask) == val, 200, 1000*1000)) { ++ ithc_log_regs(ithc); + pci_err(ithc->pci, "timed out waiting for reg 0x%04x mask 0x%02x val 0x%02x\n", + reg_num(reg), mask, val); + return -ETIMEDOUT; + } ++ ithc_log_regs(ithc); + pci_dbg(ithc->pci, "done waiting\n"); + return 0; + } + +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode) ++static void calc_ltr(u64 *ns, unsigned int *val, unsigned int *scale) + { +- pci_dbg(ithc->pci, "setting SPI speed to %i, mode %i\n", speed, mode); +- if (mode == 3) +- mode = 2; ++ unsigned int s = 0; ++ u64 v = *ns; ++ while (v > 0x3ff) { ++ s++; ++ v >>= 5; ++ } ++ if (s > 5) { ++ s = 5; ++ v = 0x3ff; ++ } ++ *val = v; ++ *scale = s; ++ *ns = v << (5 * s); ++} ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns) ++{ ++ unsigned int active_val, active_scale, idle_val, idle_scale; ++ calc_ltr(&active_ltr_ns, &active_val, &active_scale); ++ calc_ltr(&idle_ltr_ns, &idle_val, &idle_scale); ++ pci_dbg(ithc->pci, "setting active LTR value to %llu ns, idle LTR value to %llu ns\n", ++ active_ltr_ns, idle_ltr_ns); ++ writel(LTR_CONFIG_ENABLE_ACTIVE | LTR_CONFIG_ENABLE_IDLE | LTR_CONFIG_APPLY | ++ LTR_CONFIG_ACTIVE_LTR_SCALE(active_scale) | LTR_CONFIG_ACTIVE_LTR_VALUE(active_val) | ++ LTR_CONFIG_IDLE_LTR_SCALE(idle_scale) | LTR_CONFIG_IDLE_LTR_VALUE(idle_val), ++ &ithc->regs->ltr_config); ++} ++ ++void ithc_set_ltr_idle(struct ithc *ithc) ++{ ++ u32 ltr = readl(&ithc->regs->ltr_config); ++ switch (ltr & (LTR_CONFIG_STATUS_ACTIVE | LTR_CONFIG_STATUS_IDLE)) { ++ case LTR_CONFIG_STATUS_IDLE: ++ break; ++ case LTR_CONFIG_STATUS_ACTIVE: ++ writel(ltr | LTR_CONFIG_TOGGLE | LTR_CONFIG_APPLY, &ithc->regs->ltr_config); ++ break; ++ default: ++ pci_err(ithc->pci, "invalid LTR state 0x%08x\n", ltr); ++ break; ++ } ++} ++ ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode) ++{ ++ if (clkdiv == 0 || clkdiv > 7 || read_mode > SPI_MODE_QUAD || write_mode > SPI_MODE_QUAD) ++ return -EINVAL; ++ static const char * const modes[] = { "single", "dual", "quad" }; ++ pci_dbg(ithc->pci, "setting SPI frequency to %i Hz, %s read, %s write\n", ++ SPI_CLK_FREQ_BASE / (clkdiv * (clkdiv8 ? 8 : 1)), ++ modes[read_mode], modes[write_mode]); + bitsl(&ithc->regs->spi_config, +- SPI_CONFIG_MODE(0xff) | SPI_CONFIG_SPEED(0xff) | SPI_CONFIG_UNKNOWN_18(0xff) | SPI_CONFIG_SPEED2(0xff), +- SPI_CONFIG_MODE(mode) | SPI_CONFIG_SPEED(speed) | SPI_CONFIG_UNKNOWN_18(0) | SPI_CONFIG_SPEED2(speed)); ++ SPI_CONFIG_READ_MODE(0xff) | SPI_CONFIG_READ_CLKDIV(0xff) | ++ SPI_CONFIG_WRITE_MODE(0xff) | SPI_CONFIG_WRITE_CLKDIV(0xff) | ++ SPI_CONFIG_CLKDIV_8, ++ SPI_CONFIG_READ_MODE(read_mode) | SPI_CONFIG_READ_CLKDIV(clkdiv) | ++ SPI_CONFIG_WRITE_MODE(write_mode) | SPI_CONFIG_WRITE_CLKDIV(clkdiv) | ++ (clkdiv8 ? SPI_CONFIG_CLKDIV_8 : 0)); + return 0; + } + + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data) + { +- pci_dbg(ithc->pci, "SPI command %u, size %u, offset %u\n", command, size, offset); ++ pci_dbg(ithc->pci, "SPI command %u, size %u, offset 0x%x\n", command, size, offset); + if (size > sizeof(ithc->regs->spi_cmd.data)) + return -EINVAL; + +diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h +index d4007d9e2bacc..a9d2364546442 100644 +--- a/drivers/hid/ithc/ithc-regs.h ++++ b/drivers/hid/ithc/ithc-regs.h +@@ -1,14 +1,34 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + ++#define LTR_CONFIG_ENABLE_ACTIVE BIT(0) ++#define LTR_CONFIG_TOGGLE BIT(1) ++#define LTR_CONFIG_ENABLE_IDLE BIT(2) ++#define LTR_CONFIG_APPLY BIT(3) ++#define LTR_CONFIG_IDLE_LTR_SCALE(x) (((x) & 7) << 4) ++#define LTR_CONFIG_IDLE_LTR_VALUE(x) (((x) & 0x3ff) << 7) ++#define LTR_CONFIG_ACTIVE_LTR_SCALE(x) (((x) & 7) << 17) ++#define LTR_CONFIG_ACTIVE_LTR_VALUE(x) (((x) & 0x3ff) << 20) ++#define LTR_CONFIG_STATUS_ACTIVE BIT(30) ++#define LTR_CONFIG_STATUS_IDLE BIT(31) ++ + #define CONTROL_QUIESCE BIT(1) + #define CONTROL_IS_QUIESCED BIT(2) + #define CONTROL_NRESET BIT(3) ++#define CONTROL_UNKNOWN_24(x) (((x) & 3) << 24) + #define CONTROL_READY BIT(29) + +-#define SPI_CONFIG_MODE(x) (((x) & 3) << 2) +-#define SPI_CONFIG_SPEED(x) (((x) & 7) << 4) +-#define SPI_CONFIG_UNKNOWN_18(x) (((x) & 3) << 18) +-#define SPI_CONFIG_SPEED2(x) (((x) & 0xf) << 20) // high bit = high speed mode? ++#define SPI_CONFIG_READ_MODE(x) (((x) & 3) << 2) ++#define SPI_CONFIG_READ_CLKDIV(x) (((x) & 7) << 4) ++#define SPI_CONFIG_READ_PACKET_SIZE(x) (((x) & 0x1ff) << 7) ++#define SPI_CONFIG_WRITE_MODE(x) (((x) & 3) << 18) ++#define SPI_CONFIG_WRITE_CLKDIV(x) (((x) & 7) << 20) ++#define SPI_CONFIG_CLKDIV_8 BIT(23) // additionally divide clk by 8, for both read and write ++#define SPI_CONFIG_WRITE_PACKET_SIZE(x) (((x) & 0xff) << 24) ++ ++#define SPI_CLK_FREQ_BASE 125000000 ++#define SPI_MODE_SINGLE 0 ++#define SPI_MODE_DUAL 1 ++#define SPI_MODE_QUAD 2 + + #define ERROR_CONTROL_UNKNOWN_0 BIT(0) + #define ERROR_CONTROL_DISABLE_DMA BIT(1) // clears DMA_RX_CONTROL_ENABLE when a DMA error occurs +@@ -53,33 +73,71 @@ + #define DMA_TX_STATUS_UNKNOWN_2 BIT(2) + #define DMA_TX_STATUS_UNKNOWN_3 BIT(3) // busy? + ++#define INPUT_HEADER_VERSION(x) ((x) & 0xf) ++#define INPUT_HEADER_REPORT_LENGTH(x) (((x) >> 8) & 0x3fff) ++#define INPUT_HEADER_SYNC(x) ((x) >> 24) ++#define INPUT_HEADER_VERSION_VALUE 3 ++#define INPUT_HEADER_SYNC_VALUE 0x5a ++ ++#define QUICKSPI_CONFIG1_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG1_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG1_UNKNOWN_10(x) (((x) & 0x1f) << 10) ++#define QUICKSPI_CONFIG1_UNKNOWN_16(x) (((x) & 0xffff) << 16) ++ ++#define QUICKSPI_CONFIG2_UNKNOWN_0(x) (((x) & 0x1f) << 0) ++#define QUICKSPI_CONFIG2_UNKNOWN_5(x) (((x) & 0x1f) << 5) ++#define QUICKSPI_CONFIG2_UNKNOWN_12(x) (((x) & 0xf) << 12) ++#define QUICKSPI_CONFIG2_UNKNOWN_16 BIT(16) ++#define QUICKSPI_CONFIG2_UNKNOWN_17 BIT(17) ++#define QUICKSPI_CONFIG2_DISABLE_READ_ADDRESS_INCREMENT BIT(24) ++#define QUICKSPI_CONFIG2_DISABLE_WRITE_ADDRESS_INCREMENT BIT(25) ++#define QUICKSPI_CONFIG2_ENABLE_WRITE_STREAMING_MODE BIT(27) ++#define QUICKSPI_CONFIG2_IRQ_POLARITY BIT(28) ++ + #define DMA_RX_CONTROL_ENABLE BIT(0) + #define DMA_RX_CONTROL_IRQ_UNKNOWN_1 BIT(1) // rx1 only? + #define DMA_RX_CONTROL_IRQ_ERROR BIT(3) // rx1 only? +-#define DMA_RX_CONTROL_IRQ_UNKNOWN_4 BIT(4) // rx0 only? ++#define DMA_RX_CONTROL_IRQ_READY BIT(4) // rx0 only + #define DMA_RX_CONTROL_IRQ_DATA BIT(5) + ++#define DMA_RX_CONTROL2_UNKNOWN_4 BIT(4) // rx1 only? + #define DMA_RX_CONTROL2_UNKNOWN_5 BIT(5) // rx0 only? + #define DMA_RX_CONTROL2_RESET BIT(7) // resets ringbuffer indices + + #define DMA_RX_WRAP_FLAG BIT(7) + + #define DMA_RX_STATUS_ERROR BIT(3) +-#define DMA_RX_STATUS_UNKNOWN_4 BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) ++#define DMA_RX_STATUS_READY BIT(4) // set in rx0 after using CONTROL_NRESET when it becomes possible to read config (can take >100ms) + #define DMA_RX_STATUS_HAVE_DATA BIT(5) + #define DMA_RX_STATUS_ENABLED BIT(8) + ++#define INIT_UNKNOWN_GUC_2 BIT(2) ++#define INIT_UNKNOWN_3 BIT(3) ++#define INIT_UNKNOWN_GUC_4 BIT(4) ++#define INIT_UNKNOWN_5 BIT(5) ++#define INIT_UNKNOWN_31 BIT(31) ++ + // COUNTER_RESET can be written to counter registers to reset them to zero. However, in some cases this can mess up the THC. + #define COUNTER_RESET BIT(31) + + struct ithc_registers { +- /* 0000 */ u32 _unknown_0000[1024]; ++ /* 0000 */ u32 _unknown_0000[5]; ++ /* 0014 */ u32 ltr_config; ++ /* 0018 */ u32 _unknown_0018[1018]; + /* 1000 */ u32 _unknown_1000; + /* 1004 */ u32 _unknown_1004; + /* 1008 */ u32 control_bits; + /* 100c */ u32 _unknown_100c; + /* 1010 */ u32 spi_config; +- /* 1014 */ u32 _unknown_1014[3]; ++ /* 1014 */ u8 read_opcode; // maybe for header? ++ /* 1015 */ u8 read_opcode_quad; ++ /* 1016 */ u8 read_opcode_dual; ++ /* 1017 */ u8 read_opcode_single; ++ /* 1018 */ u8 write_opcode; // not used? ++ /* 1019 */ u8 write_opcode_quad; ++ /* 101a */ u8 write_opcode_dual; ++ /* 101b */ u8 write_opcode_single; ++ /* 101c */ u32 _unknown_101c; + /* 1020 */ u32 error_control; + /* 1024 */ u32 error_status; // write to clear + /* 1028 */ u32 error_flags; // write to clear +@@ -100,12 +158,19 @@ struct ithc_registers { + /* 109a */ u8 _unknown_109a; + /* 109b */ u8 num_prds; + /* 109c */ u32 status; // write to clear ++ /* 10a0 */ u32 _unknown_10a0[5]; ++ /* 10b4 */ u32 spi_addr; + } dma_tx; +- /* 10a0 */ u32 _unknown_10a0[7]; +- /* 10bc */ u32 state; // is 0xe0000402 (dev config val 0) after CONTROL_NRESET, 0xe0000461 after first touch, 0xe0000401 after DMA_RX_CODE_RESET ++ /* 10b8 */ u32 spi_header_addr; ++ union { ++ /* 10bc */ u32 irq_cause; // in legacy THC mode ++ /* 10bc */ u32 input_header; // in QuickSPI mode (see HIDSPI spec) ++ }; + /* 10c0 */ u32 _unknown_10c0[8]; + /* 10e0 */ u32 _unknown_10e0_counters[3]; +- /* 10ec */ u32 _unknown_10ec[5]; ++ /* 10ec */ u32 quickspi_config1; ++ /* 10f0 */ u32 quickspi_config2; ++ /* 10f4 */ u32 _unknown_10f4[3]; + struct { + /* 1100/1200 */ u64 addr; // cannot be written with writeq(), must use lo_hi_writeq() + /* 1108/1208 */ u8 num_bufs; +@@ -120,70 +185,30 @@ struct ithc_registers { + /* 1118/1218 */ u64 _unknown_1118_guc_addr; + /* 1120/1220 */ u32 _unknown_1120_guc; + /* 1124/1224 */ u32 _unknown_1124_guc; +- /* 1128/1228 */ u32 unknown_init_bits; // bit 2 = guc related, bit 3 = rx1 related, bit 4 = guc related ++ /* 1128/1228 */ u32 init_unknown; + /* 112c/122c */ u32 _unknown_112c; + /* 1130/1230 */ u64 _unknown_1130_guc_addr; + /* 1138/1238 */ u32 _unknown_1138_guc; + /* 113c/123c */ u32 _unknown_113c; + /* 1140/1240 */ u32 _unknown_1140_guc; +- /* 1144/1244 */ u32 _unknown_1144[23]; ++ /* 1144/1244 */ u32 _unknown_1144[11]; ++ /* 1170/1270 */ u32 spi_addr; ++ /* 1174/1274 */ u32 _unknown_1174[11]; + /* 11a0/12a0 */ u32 _unknown_11a0_counters[6]; + /* 11b8/12b8 */ u32 _unknown_11b8[18]; + } dma_rx[2]; + }; + static_assert(sizeof(struct ithc_registers) == 0x1300); + +-#define DEVCFG_DMA_RX_SIZE(x) ((((x) & 0x3fff) + 1) << 6) +-#define DEVCFG_DMA_TX_SIZE(x) (((((x) >> 14) & 0x3ff) + 1) << 6) +- +-#define DEVCFG_TOUCH_MASK 0x3f +-#define DEVCFG_TOUCH_ENABLE BIT(0) +-#define DEVCFG_TOUCH_UNKNOWN_1 BIT(1) +-#define DEVCFG_TOUCH_UNKNOWN_2 BIT(2) +-#define DEVCFG_TOUCH_UNKNOWN_3 BIT(3) +-#define DEVCFG_TOUCH_UNKNOWN_4 BIT(4) +-#define DEVCFG_TOUCH_UNKNOWN_5 BIT(5) +-#define DEVCFG_TOUCH_UNKNOWN_6 BIT(6) +- +-#define DEVCFG_DEVICE_ID_TIC 0x43495424 // "$TIC" +- +-#define DEVCFG_SPI_MAX_FREQ(x) (((x) >> 1) & 0xf) // high bit = use high speed mode? +-#define DEVCFG_SPI_MODE(x) (((x) >> 6) & 3) +-#define DEVCFG_SPI_UNKNOWN_8(x) (((x) >> 8) & 0x3f) +-#define DEVCFG_SPI_NEEDS_HEARTBEAT BIT(20) // TODO implement heartbeat +-#define DEVCFG_SPI_HEARTBEAT_INTERVAL(x) (((x) >> 21) & 7) +-#define DEVCFG_SPI_UNKNOWN_25 BIT(25) +-#define DEVCFG_SPI_UNKNOWN_26 BIT(26) +-#define DEVCFG_SPI_UNKNOWN_27 BIT(27) +-#define DEVCFG_SPI_DELAY(x) (((x) >> 28) & 7) // TODO use this +-#define DEVCFG_SPI_USE_EXT_READ_CFG BIT(31) // TODO use this? +- +-struct ithc_device_config { // (Example values are from an SP7+.) +- u32 _unknown_00; // 00 = 0xe0000402 (0xe0000401 after DMA_RX_CODE_RESET) +- u32 _unknown_04; // 04 = 0x00000000 +- u32 dma_buf_sizes; // 08 = 0x000a00ff +- u32 touch_cfg; // 0c = 0x0000001c +- u32 _unknown_10; // 10 = 0x0000001c +- u32 device_id; // 14 = 0x43495424 = "$TIC" +- u32 spi_config; // 18 = 0xfda00a2e +- u16 vendor_id; // 1c = 0x045e = Microsoft Corp. +- u16 product_id; // 1e = 0x0c1a +- u32 revision; // 20 = 0x00000001 +- u32 fw_version; // 24 = 0x05008a8b = 5.0.138.139 (this value looks more random on newer devices) +- u32 _unknown_28; // 28 = 0x00000000 +- u32 fw_mode; // 2c = 0x00000000 (for fw update?) +- u32 _unknown_30; // 30 = 0x00000000 +- u32 _unknown_34; // 34 = 0x0404035e (u8,u8,u8,u8 = version?) +- u32 _unknown_38; // 38 = 0x000001c0 (0x000001c1 after DMA_RX_CODE_RESET) +- u32 _unknown_3c; // 3c = 0x00000002 +-}; +- + void bitsl(__iomem u32 *reg, u32 mask, u32 val); + void bitsb(__iomem u8 *reg, u8 mask, u8 val); + #define bitsl_set(reg, x) bitsl(reg, x, x) + #define bitsb_set(reg, x) bitsb(reg, x, x) + int waitl(struct ithc *ithc, __iomem u32 *reg, u32 mask, u32 val); + int waitb(struct ithc *ithc, __iomem u8 *reg, u8 mask, u8 val); +-int ithc_set_spi_config(struct ithc *ithc, u8 speed, u8 mode); ++ ++void ithc_set_ltr_config(struct ithc *ithc, u64 active_ltr_ns, u64 idle_ltr_ns); ++void ithc_set_ltr_idle(struct ithc *ithc); ++int ithc_set_spi_config(struct ithc *ithc, u8 clkdiv, bool clkdiv8, u8 read_mode, u8 write_mode); + int ithc_spi_command(struct ithc *ithc, u8 command, u32 offset, u32 size, void *data); + +diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h +index 028e55a4ec53e..e90c380444325 100644 +--- a/drivers/hid/ithc/ithc.h ++++ b/drivers/hid/ithc/ithc.h +@@ -1,20 +1,19 @@ + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ + +-#include <linux/module.h> +-#include <linux/input.h> +-#include <linux/hid.h> ++#include <linux/acpi.h> ++#include <linux/debugfs.h> ++#include <linux/delay.h> + #include <linux/dma-mapping.h> ++#include <linux/hid.h> + #include <linux/highmem.h> +-#include <linux/pci.h> ++#include <linux/input.h> + #include <linux/io-64-nonatomic-lo-hi.h> + #include <linux/iopoll.h> +-#include <linux/delay.h> + #include <linux/kthread.h> + #include <linux/miscdevice.h> +-#include <linux/debugfs.h> ++#include <linux/module.h> ++#include <linux/pci.h> + #include <linux/poll.h> +-#include <linux/timer.h> +-#include <linux/pm_qos.h> + + #define DEVNAME "ithc" + #define DEVFULLNAME "Intel Touch Host Controller" +@@ -27,10 +26,37 @@ + + #define NUM_RX_BUF 16 + ++// PCI device IDs: ++// Lakefield ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT1 0x98d0 ++#define PCI_DEVICE_ID_INTEL_THC_LKF_PORT2 0x98d1 ++// Tiger Lake ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT1 0xa0d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_LP_PORT2 0xa0d1 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT1 0x43d0 ++#define PCI_DEVICE_ID_INTEL_THC_TGL_H_PORT2 0x43d1 ++// Alder Lake ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT1 0x7ad8 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_S_PORT2 0x7ad9 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT1 0x51d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_P_PORT2 0x51d1 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT1 0x54d0 ++#define PCI_DEVICE_ID_INTEL_THC_ADL_M_PORT2 0x54d1 ++// Raptor Lake ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT1 0x7a58 ++#define PCI_DEVICE_ID_INTEL_THC_RPL_S_PORT2 0x7a59 ++// Meteor Lake ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT1 0x7e48 ++#define PCI_DEVICE_ID_INTEL_THC_MTL_PORT2 0x7e4a ++ + struct ithc; + + #include "ithc-regs.h" ++#include "ithc-hid.h" + #include "ithc-dma.h" ++#include "ithc-legacy.h" ++#include "ithc-quickspi.h" ++#include "ithc-debug.h" + + struct ithc { + char phys[32]; +@@ -38,30 +64,21 @@ struct ithc { + int irq; + struct task_struct *poll_thread; + +- struct pm_qos_request activity_qos; +- struct hrtimer activity_start_timer; +- struct hrtimer activity_end_timer; +- ktime_t last_rx_time; +- unsigned int cur_rx_seq_count; +- unsigned int cur_rx_seq_errors; +- +- struct hid_device *hid; +- bool hid_parse_done; +- wait_queue_head_t wait_hid_parse; +- wait_queue_head_t wait_hid_get_feature; +- struct mutex hid_get_feature_mutex; +- void *hid_get_feature_buf; +- size_t hid_get_feature_size; +- + struct ithc_registers __iomem *regs; + struct ithc_registers *prev_regs; // for debugging +- struct ithc_device_config config; + struct ithc_dma_rx dma_rx[2]; + struct ithc_dma_tx dma_tx; ++ struct ithc_hid hid; ++ ++ bool use_quickspi; ++ bool have_config; ++ u16 vendor_id; ++ u16 product_id; ++ u32 product_rev; ++ u32 max_rx_size; ++ u32 max_tx_size; ++ u32 legacy_touch_cfg; + }; + + int ithc_reset(struct ithc *ithc); +-void ithc_set_active(struct ithc *ithc, unsigned int duration_us); +-int ithc_debug_init(struct ithc *ithc); +-void ithc_log_regs(struct ithc *ithc); + +-- +2.45.1 + +From b4563a0da733d5759de36d9e555ce81324dca286 Mon Sep 17 00:00:00 2001 +From: Hans de Goede <hdegoede@redhat.com> +Date: Thu, 9 May 2024 16:15:49 +0200 +Subject: [PATCH] serial: Clear UPF_DEAD before calling + tty_port_register_device_attr_serdev() + +If a serdev_device_driver is already loaded for a serdev_tty_port when it +gets registered by tty_port_register_device_attr_serdev() then that +driver's probe() method will be called immediately. + +The serdev_device_driver's probe() method should then be able to call +serdev_device_open() successfully, but because UPF_DEAD is still dead +serdev_device_open() will fail with -ENXIO in this scenario: + + serdev_device_open() + ctrl->ops->open() /* this callback being ttyport_open() */ + tty->ops->open() /* this callback being uart_open() */ + tty_port_open() + port->ops->activate() /* this callback being uart_port_activate() */ + Find bit UPF_DEAD is set in uport->flags and fail with errno -ENXIO. + +Fix this be clearing UPF_DEAD before tty_port_register_device_attr_serdev() +note this only moves up the UPD_DEAD clearing a small bit, before: + + tty_port_register_device_attr_serdev(); + mutex_unlock(&tty_port.mutex); + uart_port.flags &= ~UPF_DEAD; + mutex_unlock(&port_mutex); + +after: + + uart_port.flags &= ~UPF_DEAD; + tty_port_register_device_attr_serdev(); + mutex_unlock(&tty_port.mutex); + mutex_unlock(&port_mutex); + +Reported-by: Weifeng Liu <weifeng.liu.z@gmail.com> +Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@gmail.com/ +Tested-by: Weifeng Liu <weifeng.liu.z@gmail.com> +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +Link: https://lore.kernel.org/r/20240509141549.63704-1-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Patchset: surface-sam +--- + drivers/tty/serial/serial_core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index c476d884356db..b47a277978a0b 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -3211,6 +3211,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u + if (uport->attr_group) + uport->tty_groups[1] = uport->attr_group; + ++ /* Ensure serdev drivers can call serdev_device_open() right away */ ++ uport->flags &= ~UPF_DEAD; ++ + /* + * Register the port whether it's detected or not. This allows + * setserial to be used to alter this port's parameters. +@@ -3221,6 +3224,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u + if (!IS_ERR(tty_dev)) { + device_set_wakeup_capable(tty_dev, 1); + } else { ++ uport->flags |= UPF_DEAD; + dev_err(uport->dev, "Cannot register tty device on line %d\n", + uport->line); + } +@@ -3426,8 +3430,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) + if (ret) + goto err_unregister_port_dev; + +- port->flags &= ~UPF_DEAD; +- + mutex_unlock(&port_mutex); + + return 0; +-- +2.45.1 + +From 0864ded554efe90dd9603b61e82c604481ee5125 Mon Sep 17 00:00:00 2001 +From: Weifeng Liu <weifeng.liu.z@gmail.com> +Date: Sun, 5 May 2024 21:07:50 +0800 +Subject: [PATCH] platform/surface: aggregator: Log critical errors during SAM + probing + +Emits messages upon errors during probing of SAM. Hopefully this could +provide useful context to user for the purpose of diagnosis when +something miserable happen. + +Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> +Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> +Signed-off-by: Weifeng Liu <weifeng.liu.z@gmail.com> +Link: https://lore.kernel.org/r/20240505130800.2546640-3-weifeng.liu.z@gmail.com +Reviewed-by: Hans de Goede <hdegoede@redhat.com> +Signed-off-by: Hans de Goede <hdegoede@redhat.com> +Patchset: surface-sam +--- + drivers/platform/surface/aggregator/core.c | 42 ++++++++++++++-------- + 1 file changed, 28 insertions(+), 14 deletions(-) + +diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c +index ba550eaa06fcf..797d0645bd77f 100644 +--- a/drivers/platform/surface/aggregator/core.c ++++ b/drivers/platform/surface/aggregator/core.c +@@ -618,15 +618,17 @@ static const struct acpi_gpio_mapping ssam_acpi_gpios[] = { + + static int ssam_serial_hub_probe(struct serdev_device *serdev) + { +- struct acpi_device *ssh = ACPI_COMPANION(&serdev->dev); ++ struct device *dev = &serdev->dev; ++ struct acpi_device *ssh = ACPI_COMPANION(dev); + struct ssam_controller *ctrl; + acpi_status astatus; + int status; + +- if (gpiod_count(&serdev->dev, NULL) < 0) +- return -ENODEV; ++ status = gpiod_count(dev, NULL); ++ if (status < 0) ++ return dev_err_probe(dev, status, "no GPIO found\n"); + +- status = devm_acpi_dev_add_driver_gpios(&serdev->dev, ssam_acpi_gpios); ++ status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios); + if (status) + return status; + +@@ -637,8 +639,10 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + + /* Initialize controller. */ + status = ssam_controller_init(ctrl, serdev); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to initialize ssam controller\n"); + goto err_ctrl_init; ++ } + + ssam_controller_lock(ctrl); + +@@ -646,12 +650,14 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + serdev_device_set_drvdata(serdev, ctrl); + serdev_device_set_client_ops(serdev, &ssam_serdev_ops); + status = serdev_device_open(serdev); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to open serdev device\n"); + goto err_devopen; ++ } + + astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev); + if (ACPI_FAILURE(astatus)) { +- status = -ENXIO; ++ status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n"); + goto err_devinit; + } + +@@ -667,25 +673,33 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + * states. + */ + status = ssam_log_firmware_version(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to get firmware version\n"); + goto err_initrq; ++ } + + status = ssam_ctrl_notif_d0_entry(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "D0-entry notification failed\n"); + goto err_initrq; ++ } + + status = ssam_ctrl_notif_display_on(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "display-on notification failed\n"); + goto err_initrq; ++ } + +- status = sysfs_create_group(&serdev->dev.kobj, &ssam_sam_group); ++ status = sysfs_create_group(&dev->kobj, &ssam_sam_group); + if (status) + goto err_initrq; + + /* Set up IRQ. */ + status = ssam_irq_setup(ctrl); +- if (status) ++ if (status) { ++ dev_err_probe(dev, status, "failed to setup IRQ\n"); + goto err_irq; ++ } + + /* Finally, set main controller reference. */ + status = ssam_try_set_controller(ctrl); +@@ -702,7 +716,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + * resumed. In short, this causes some spurious unwanted wake-ups. + * For now let's thus default power/wakeup to false. + */ +- device_set_wakeup_capable(&serdev->dev, true); ++ device_set_wakeup_capable(dev, true); + acpi_dev_clear_dependencies(ssh); + + return 0; +@@ -710,7 +724,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev) + err_mainref: + ssam_irq_free(ctrl); + err_irq: +- sysfs_remove_group(&serdev->dev.kobj, &ssam_sam_group); ++ sysfs_remove_group(&dev->kobj, &ssam_sam_group); + err_initrq: + ssam_controller_lock(ctrl); + ssam_controller_shutdown(ctrl); +-- +2.45.1 + +From d44985653441ba783a830bd5efde2fcf3a3ea271 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz <luzmaximilian@gmail.com> +Date: Fri, 19 Apr 2024 20:41:47 +0200 +Subject: [PATCH] platform/surface: aggregator: Fix warning when controller is + destroyed in probe + +There is a small window in ssam_serial_hub_probe() where the controller +is initialized but has not been started yet. Specifically, between +ssam_controller_init() and ssam_controller_start(). Any failure in this +window, for example caused by a failure of serdev_device_open(), +currently results in an incorrect warning being emitted. + +In particular, any failure in this window results in the controller +being destroyed via ssam_controller_destroy(). This function checks the +state of the controller and, in an attempt to validate that the +controller has been cleanly shut down before we try and deallocate any +resources, emits a warning if that state is not SSAM_CONTROLLER_STOPPED. + +However, since we have only just initialized the controller and have not +yet started it, its state is SSAM_CONTROLLER_INITIALIZED. Note that this +is the only point at which the controller has this state, as it will +change after we start the controller with ssam_controller_start() and +never revert back. Further, at this point no communication has taken +place and the sender and receiver threads have not been started yet (and +we may not even have an open serdev device either). + +Therefore, it is perfectly safe to call ssam_controller_destroy() with a +state of SSAM_CONTROLLER_INITIALIZED. This, however, means that the +warning currently being emitted is incorrect. Fix it by extending the +check. + +Fixes: c167b9c7e3d6 ("platform/surface: Add Surface Aggregator subsystem") +Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> +Patchset: surface-sam +--- + drivers/platform/surface/aggregator/controller.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c +index 7fc602e01487d..7e89f547999b2 100644 +--- a/drivers/platform/surface/aggregator/controller.c ++++ b/drivers/platform/surface/aggregator/controller.c +@@ -1354,7 +1354,8 @@ void ssam_controller_destroy(struct ssam_controller *ctrl) + if (ctrl->state == SSAM_CONTROLLER_UNINITIALIZED) + return; + +- WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED); ++ WARN_ON(ctrl->state != SSAM_CONTROLLER_STOPPED && ++ ctrl->state != SSAM_CONTROLLER_INITIALIZED); + + /* + * Note: New events could still have been received after the previous +-- +2.45.1 + +From 6b6f860bbef0ba3f10f8dc151ac4e27d0a34c223 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sun, 22 Oct 2023 14:57:11 +0200 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -5695,10 +8577,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 aeb3feae40ff..2bc4977037fc 100644 +index 035d6b4105cd6..74688a2ed4b2e 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -367,6 +367,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { +@@ -374,6 +374,9 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Laptop Go 2 */ { "MSHW0290", (unsigned long)ssam_node_group_slg1 }, @@ -5709,9 +8591,9 @@ index aeb3feae40ff..2bc4977037fc 100644 { "MSHW0123", (unsigned long)ssam_node_group_sls }, -- -2.44.0 +2.45.1 -From 7dedc84364f9c1fb73d271c859dce19b4a9644d6 Mon Sep 17 00:00:00 2001 +From 31b312c25822404e52a81de2525da5c7bae12864 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Mon, 20 Nov 2023 19:47:00 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -5729,10 +8611,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 2bc4977037fc..26cb6229ad16 100644 +index 74688a2ed4b2e..f02a933160ff2 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c -@@ -247,8 +247,8 @@ static const struct software_node *ssam_node_group_sl5[] = { +@@ -253,8 +253,8 @@ static const struct software_node *ssam_node_group_sl5[] = { NULL, }; @@ -5743,7 +8625,7 @@ index 2bc4977037fc..26cb6229ad16 100644 &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, -@@ -263,6 +263,20 @@ static const struct software_node *ssam_node_group_sls[] = { +@@ -269,6 +269,20 @@ static const struct software_node *ssam_node_group_sls[] = { NULL, }; @@ -5764,7 +8646,7 @@ index 2bc4977037fc..26cb6229ad16 100644 /* Devices for Surface Laptop Go. */ static const struct software_node *ssam_node_group_slg1[] = { &ssam_node_root, -@@ -370,8 +384,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { +@@ -377,8 +391,11 @@ static const struct acpi_device_id ssam_platform_hub_match[] = { /* Surface Laptop Go 3 */ { "MSHW0440", (unsigned long)ssam_node_group_slg1 }, @@ -5779,277 +8661,66 @@ index 2bc4977037fc..26cb6229ad16 100644 { }, }; -- -2.44.0 +2.45.1 -From 96a7b3dd527f3e1b97e2d089a727c16cd5045aa5 Mon Sep 17 00:00:00 2001 -From: Ivor Wanders <ivor@iwanders.net> -Date: Mon, 18 Dec 2023 19:21:32 -0500 -Subject: [PATCH] platform/surface: aggregator_registry: add entry for fan - speed +From 42f6d14bda5e69c2b5a8d27cfcbd063a5922f876 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz <luzmaximilian@gmail.com> +Date: Sun, 9 Jun 2024 20:05:57 +0200 +Subject: [PATCH] platform/surface: aggregator_registry: Add support for + Surface Laptop 6 -Add an entry for the fan speed function. -Add this new entry to the Surface Pro 9 group. +Add SAM client device nodes for the Surface Laptop Studio 6 (SL6). The +SL6 is similar to the SL5, with the typical battery/AC, platform +profile, and HID nodes. It also has support for the newly supported fan +interface. -Signed-off-by: Ivor Wanders <ivor@iwanders.net> -Link: https://github.com/linux-surface/kernel/pull/144 -Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> +Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> Patchset: surface-sam --- - drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ - 1 file changed, 7 insertions(+) + .../surface/surface_aggregator_registry.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 26cb6229ad16..f02a933160ff 100644 +index f02a933160ff2..34df1bdad83bd 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, +@@ -253,6 +253,22 @@ static const struct software_node *ssam_node_group_sl5[] = { + NULL, }; -+/* Fan speed function. */ -+static const struct software_node ssam_node_fan_speed = { -+ .name = "ssam:01:05:01:01:01", -+ .parent = &ssam_node_root, -+}; -+ - /* Tablet-mode switch via KIP subsystem. */ - static const struct software_node ssam_node_kip_tablet_switch = { - .name = "ssam:01:0e:01:00:01", -@@ -319,6 +325,7 @@ static const struct software_node *ssam_node_group_sp9[] = { - &ssam_node_bat_ac, - &ssam_node_bat_main, - &ssam_node_tmp_pprof, ++/* Devices for Surface Laptop 6. */ ++static const struct software_node *ssam_node_group_sl6[] = { ++ &ssam_node_root, ++ &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, --- -2.44.0 - -From b4eb65349df9859f65aa9990c24c5036d35382da Mon Sep 17 00:00:00 2001 -From: Ivor Wanders <ivor@iwanders.net> -Date: Thu, 30 Nov 2023 20:20:24 -0500 -Subject: [PATCH] hwmon: add fan speed monitoring driver for Surface devices - -Adds a driver that provides read only access to the fan speed for Microsoft -Surface Pro devices. The fan speed is always regulated by the EC and cannot -be influenced directly. - -Signed-off-by: Ivor Wanders <ivor@iwanders.net> -Link: https://github.com/linux-surface/kernel/pull/144 -Patchset: surface-sam ---- - Documentation/hwmon/index.rst | 1 + - Documentation/hwmon/surface_fan.rst | 25 ++++++++ - MAINTAINERS | 8 +++ - drivers/hwmon/Kconfig | 13 ++++ - drivers/hwmon/Makefile | 1 + - drivers/hwmon/surface_fan.c | 93 +++++++++++++++++++++++++++++ - 6 files changed, 141 insertions(+) - create mode 100644 Documentation/hwmon/surface_fan.rst - create mode 100644 drivers/hwmon/surface_fan.c - -diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst -index c7ed1f73ac06..58be92e94a8d 100644 ---- a/Documentation/hwmon/index.rst -+++ b/Documentation/hwmon/index.rst -@@ -208,6 +208,7 @@ Hardware Monitoring Kernel Drivers - smsc47m1 - sparx5-temp - stpddc60 -+ surface_fan - sy7636a-hwmon - tc654 - tc74 -diff --git a/Documentation/hwmon/surface_fan.rst b/Documentation/hwmon/surface_fan.rst -new file mode 100644 -index 000000000000..07942574c4f0 ---- /dev/null -+++ b/Documentation/hwmon/surface_fan.rst -@@ -0,0 +1,25 @@ -+.. SPDX-License-Identifier: GPL-2.0-or-later -+ -+Kernel driver surface_fan -+========================= -+ -+Supported Devices: -+ -+ * Microsoft Surface Pro 9 -+ -+Author: Ivor Wanders <ivor@iwanders.net> -+ -+Description -+----------- -+ -+This provides monitoring of the fan found in some Microsoft Surface Pro devices, -+like the Surface Pro 9. The fan is always controlled by the onboard controller. -+ -+Sysfs interface -+--------------- -+ -+======================= ======= ========================================= -+Name Perm Description -+======================= ======= ========================================= -+``fan1_input`` RO Current fan speed in RPM. -+======================= ======= ========================================= -diff --git a/MAINTAINERS b/MAINTAINERS -index 1aabf1c15bb3..b6416cf3f022 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -14576,6 +14576,14 @@ F: Documentation/driver-api/surface_aggregator/clients/dtx.rst - F: drivers/platform/surface/surface_dtx.c - F: include/uapi/linux/surface_aggregator/dtx.h - -+MICROSOFT SURFACE SENSOR FAN DRIVER -+M: Maximilian Luz <luzmaximilian@gmail.com> -+M: Ivor Wanders <ivor@iwanders.net> -+L: linux-hwmon@vger.kernel.org -+S: Maintained -+F: Documentation/hwmon/surface_fan.rst -+F: drivers/hwmon/surface_fan.c -+ - MICROSOFT SURFACE GPE LID SUPPORT DRIVER - M: Maximilian Luz <luzmaximilian@gmail.com> - L: platform-driver-x86@vger.kernel.org -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index a608264da87d..e762f6138970 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1994,6 +1994,19 @@ config SENSORS_SFCTEMP - This driver can also be built as a module. If so, the module - will be called sfctemp. - -+config SENSORS_SURFACE_FAN -+ tristate "Surface Fan Driver" -+ depends on SURFACE_AGGREGATOR -+ help -+ Driver that provides monitoring of the fan on Surface Pro devices that -+ have a fan, like the Surface Pro 9. -+ -+ This makes the fan's current speed accessible through the hwmon -+ system. It does not provide control over the fan, the firmware is -+ responsible for that, this driver merely provides monitoring. -+ -+ Select M or Y here, if you want to be able to read the fan's speed. -+ - config SENSORS_ADC128D818 - tristate "Texas Instruments ADC128D818" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 47be39af5c03..30cc90f40844 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -201,6 +201,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o - 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 - obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o - obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o - obj-$(CONFIG_SENSORS_TC74) += tc74.o -diff --git a/drivers/hwmon/surface_fan.c b/drivers/hwmon/surface_fan.c -new file mode 100644 -index 000000000000..7c2e3ae3eb40 ---- /dev/null -+++ b/drivers/hwmon/surface_fan.c -@@ -0,0 +1,93 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Surface Fan driver for Surface System Aggregator Module. It provides access -+ * to the fan's rpm through the hwmon system. -+ * -+ * Copyright (C) 2023 Ivor Wanders <ivor@iwanders.net> -+ */ -+ -+#include <linux/hwmon.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/surface_aggregator/device.h> -+#include <linux/types.h> -+ -+// SSAM -+SSAM_DEFINE_SYNC_REQUEST_CL_R(__ssam_fan_rpm_get, __le16, { -+ .target_category = SSAM_SSH_TC_FAN, -+ .command_id = 0x01, -+}); -+ -+// hwmon -+umode_t surface_fan_hwmon_is_visible(const void *drvdata, -+ enum hwmon_sensor_types type, u32 attr, -+ int channel) -+{ -+ return 0444; -+} -+ -+static int surface_fan_hwmon_read(struct device *dev, -+ enum hwmon_sensor_types type, u32 attr, -+ int channel, long *val) -+{ -+ struct ssam_device *sdev = dev_get_drvdata(dev); -+ int ret; -+ __le16 value; -+ -+ ret = __ssam_fan_rpm_get(sdev, &value); -+ if (ret) -+ return ret; -+ -+ *val = le16_to_cpu(value); -+ -+ return ret; -+} -+ -+static const struct hwmon_channel_info *const surface_fan_info[] = { -+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), -+ NULL -+}; -+ -+static const struct hwmon_ops surface_fan_hwmon_ops = { -+ .is_visible = surface_fan_hwmon_is_visible, -+ .read = surface_fan_hwmon_read, -+}; -+ -+static const struct hwmon_chip_info surface_fan_chip_info = { -+ .ops = &surface_fan_hwmon_ops, -+ .info = surface_fan_info, -+}; -+ -+static int surface_fan_probe(struct ssam_device *sdev) -+{ -+ struct device *hdev; -+ -+ hdev = devm_hwmon_device_register_with_info(&sdev->dev, -+ "surface_fan", sdev, -+ &surface_fan_chip_info, -+ NULL); -+ if (IS_ERR(hdev)) -+ return PTR_ERR(hdev); -+ -+ return 0; -+} -+ -+static const struct ssam_device_id ssam_fan_match[] = { -+ { SSAM_SDEV(FAN, SAM, 0x01, 0x01) }, -+ {}, ++ &ssam_node_hid_main_keyboard, ++ &ssam_node_hid_main_touchpad, ++ &ssam_node_hid_main_iid5, ++ &ssam_node_hid_sam_sensors, ++ &ssam_node_hid_sam_ucm_ucsi, ++ NULL, +}; -+MODULE_DEVICE_TABLE(ssam, ssam_fan_match); + -+static struct ssam_device_driver surface_fan = { -+ .probe = surface_fan_probe, -+ .match_table = ssam_fan_match, -+ .driver = { -+ .name = "surface_fan", -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_ssam_device_driver(surface_fan); + /* 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[] = { + /* Surface Laptop 5 */ + { "MSHW0350", (unsigned long)ssam_node_group_sl5 }, + ++ /* Surface Laptop 6 */ ++ { "MSHW0530", (unsigned long)ssam_node_group_sl5 }, + -+MODULE_AUTHOR("Ivor Wanders <ivor@iwanders.net>"); -+MODULE_DESCRIPTION("Fan Driver for Surface System Aggregator Module"); -+MODULE_LICENSE("GPL"); + /* Surface Laptop Go 1 */ + { "MSHW0118", (unsigned long)ssam_node_group_slg1 }, + -- -2.44.0 +2.45.1 -From 5c18bed9c7ad073b61e3c3686dc4bc1858f958dc Mon Sep 17 00:00:00 2001 +From 88fda328aea3bb7077cd39f854148276dcffcea3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 30 Dec 2023 18:07:54 +0100 Subject: [PATCH] hwmon: Add thermal sensor driver for Surface Aggregator @@ -6071,10 +8742,10 @@ Patchset: surface-sam create mode 100644 drivers/hwmon/surface_temp.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index e762f6138970..41261b49f8be 100644 +index 83945397b6eb1..338ef73c96a3a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig -@@ -2007,6 +2007,16 @@ config SENSORS_SURFACE_FAN +@@ -2070,6 +2070,16 @@ config SENSORS_SURFACE_FAN Select M or Y here, if you want to be able to read the fan's speed. @@ -6092,10 +8763,10 @@ index e762f6138970..41261b49f8be 100644 tristate "Texas Instruments ADC128D818" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 30cc90f40844..6644fd4598a4 100644 +index 5c31808f6378d..de8bc99719e63 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile -@@ -202,6 +202,7 @@ obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o +@@ -208,6 +208,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 @@ -6105,7 +8776,7 @@ index 30cc90f40844..6644fd4598a4 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 000000000000..48c3e826713f +index 0000000000000..48c3e826713f6 --- /dev/null +++ b/drivers/hwmon/surface_temp.c @@ -0,0 +1,165 @@ @@ -6275,9 +8946,9 @@ index 000000000000..48c3e826713f +MODULE_DESCRIPTION("Thermal sensor subsystem driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); -- -2.44.0 +2.45.1 -From 8b1e37ad9423a6fdf8a8b3bfb1e15aadefe136de Mon Sep 17 00:00:00 2001 +From 17f0ec6ef1bc95e152af3a9f2b05ea669c75d24a Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 30 Dec 2023 18:12:23 +0100 Subject: [PATCH] hwmon: surface_temp: Add support for sensor names @@ -6295,7 +8966,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 48c3e826713f..4c08926139db 100644 +index 48c3e826713f6..4c08926139dbf 100644 --- a/drivers/hwmon/surface_temp.c +++ b/drivers/hwmon/surface_temp.c @@ -17,6 +17,27 @@ @@ -6470,9 +9141,9 @@ index 48c3e826713f..4c08926139db 100644 "surface_thermal", ssam_temp, &ssam_temp_hwmon_chip_info, NULL); -- -2.44.0 +2.45.1 -From 9b490a17f59518e59cf3c77c103bf5ddc52041a3 Mon Sep 17 00:00:00 2001 +From 54bfa02fe865b9f22d79b112a5244ce81e4961f1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 30 Dec 2023 18:21:12 +0100 Subject: [PATCH] platform/surface: aggregator_registry: Add support for @@ -6488,7 +9159,7 @@ Patchset: surface-sam 1 file changed, 7 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index f02a933160ff..67686042e009 100644 +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 = { @@ -6504,7 +9175,7 @@ index f02a933160ff..67686042e009 100644 /* Fan speed function. */ static const struct software_node ssam_node_fan_speed = { .name = "ssam:01:05:01:01:01", -@@ -325,6 +331,7 @@ static const struct software_node *ssam_node_group_sp9[] = { +@@ -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, @@ -6513,9 +9184,9 @@ index f02a933160ff..67686042e009 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_kip_keyboard, -- -2.44.0 +2.45.1 -From ec0b680c0ce36ef6bffd682e10589cf5d8d467ae Mon Sep 17 00:00:00 2001 +From 06c4b5ac6b6357227e45c53643729140d794b48d Mon Sep 17 00:00:00 2001 From: Ivor Wanders <ivor@iwanders.net> Date: Sat, 16 Dec 2023 15:56:39 -0500 Subject: [PATCH] platform/surface: platform_profile: add fan profile switching @@ -6532,7 +9203,7 @@ Patchset: surface-sam 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c -index 67686042e009..058b6654a91a 100644 +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 = { @@ -6603,7 +9274,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_hid_main_keyboard, &ssam_node_hid_main_touchpad, &ssam_node_hid_main_iid5, -@@ -264,7 +278,7 @@ static const struct software_node *ssam_node_group_sls1[] = { +@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls1[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -6612,7 +9283,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -@@ -280,7 +294,7 @@ static const struct software_node *ssam_node_group_sls2[] = { +@@ -296,7 +310,7 @@ static const struct software_node *ssam_node_group_sls2[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -6621,7 +9292,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_pos_tablet_switch, &ssam_node_hid_sam_keyboard, &ssam_node_hid_sam_penstash, -@@ -294,7 +308,7 @@ static const struct software_node *ssam_node_group_slg1[] = { +@@ -310,7 +324,7 @@ static const struct software_node *ssam_node_group_slg1[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -6630,7 +9301,7 @@ index 67686042e009..058b6654a91a 100644 NULL, }; -@@ -303,7 +317,7 @@ static const struct software_node *ssam_node_group_sp7[] = { +@@ -319,7 +333,7 @@ static const struct software_node *ssam_node_group_sp7[] = { &ssam_node_root, &ssam_node_bat_ac, &ssam_node_bat_main, @@ -6639,7 +9310,7 @@ index 67686042e009..058b6654a91a 100644 NULL, }; -@@ -313,7 +327,7 @@ static const struct software_node *ssam_node_group_sp8[] = { +@@ -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, @@ -6648,7 +9319,7 @@ index 67686042e009..058b6654a91a 100644 &ssam_node_kip_tablet_switch, &ssam_node_hid_kip_keyboard, &ssam_node_hid_kip_penstash, -@@ -330,7 +344,7 @@ static const struct software_node *ssam_node_group_sp9[] = { +@@ -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, @@ -6658,7 +9329,7 @@ index 67686042e009..058b6654a91a 100644 &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 a5a3941b3f43..e54d0a8f7daa 100644 +index a5a3941b3f43a..e54d0a8f7daa5 100644 --- a/drivers/platform/surface/surface_platform_profile.c +++ b/drivers/platform/surface/surface_platform_profile.c @@ -1,7 +1,7 @@ @@ -6840,9 +9511,9 @@ index a5a3941b3f43..e54d0a8f7daa 100644 set_bit(PLATFORM_PROFILE_BALANCED, tpd->handler.choices); set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, tpd->handler.choices); -- -2.44.0 +2.45.1 -From 95b66fb97652988a7b4be5bb1deaa625e1bb3c3f Mon Sep 17 00:00:00 2001 +From bf55987e82f9ae913b51a6a269fc1a397930f049 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -6899,7 +9570,7 @@ 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 d6037a328669..a290ebc77aea 100644 +index d6037a3286690..a290ebc77aea2 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, @@ -6952,9 +9623,9 @@ index d6037a328669..a290ebc77aea 100644 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); -- -2.44.0 +2.45.1 -From 2b86ac312b956799265cdd1411d305cd2dcaf6db Mon Sep 17 00:00:00 2001 +From ebfda7ad73dd90971be10e9d6f59c51c781accbb Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sat, 13 Feb 2021 16:41:18 +0100 Subject: [PATCH] platform/surface: Add driver for Surface Book 1 dGPU switch @@ -6977,7 +9648,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 b629e82af97c..68656e8f309e 100644 +index b629e82af97c0..68656e8f309ed 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH @@ -6995,7 +9666,7 @@ index b629e82af97c..68656e8f309e 100644 tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile -index 53344330939b..7efcd0cdb532 100644 +index 53344330939bf..7efcd0cdb5329 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o @@ -7008,7 +9679,7 @@ index 53344330939b..7efcd0cdb532 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 000000000000..8b816ed8f35c +index 0000000000000..8b816ed8f35c6 --- /dev/null +++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c @@ -0,0 +1,162 @@ @@ -7175,9 +9846,9 @@ index 000000000000..8b816ed8f35c +MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); +MODULE_LICENSE("GPL"); -- -2.44.0 +2.45.1 -From 3584a6c1791dc9c9b9c3ee846621571cbfabe37e Mon Sep 17 00:00:00 2001 +From 1e315f586b0b2bc375b96bb538a3be4c0b09d1ea Mon Sep 17 00:00:00 2001 From: Sachi King <nakato@nakato.io> Date: Tue, 5 Oct 2021 00:05:09 +1100 Subject: [PATCH] Input: soc_button_array - support AMD variant Surface devices @@ -7199,7 +9870,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 f6d060377d18..b8603f74eb28 100644 +index f6d060377d189..b8603f74eb286 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 = { @@ -7252,9 +9923,9 @@ index f6d060377d18..b8603f74eb28 100644 /* -- -2.44.0 +2.45.1 -From c26bb1d0af0fe40be270d203d6aaeab28dd04a10 Mon Sep 17 00:00:00 2001 +From ac551644781bce2145c901b16779114b273c4d49 Mon Sep 17 00:00:00 2001 From: Sachi King <nakato@nakato.io> Date: Tue, 5 Oct 2021 00:22:57 +1100 Subject: [PATCH] platform/surface: surfacepro3_button: don't load on amd @@ -7275,7 +9946,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 2755601f979c..4240c98ca226 100644 +index 2755601f979cd..4240c98ca2265 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) @@ -7324,582 +9995,9 @@ index 2755601f979c..4240c98ca226 100644 -- -2.44.0 - -From b3fac417611f5bb4ae2a9bc9e828dacfe4418fbf Mon Sep 17 00:00:00 2001 -From: Maximilian Luz <luzmaximilian@gmail.com> -Date: Sat, 18 Feb 2023 01:02:49 +0100 -Subject: [PATCH] USB: quirks: Add USB_QUIRK_DELAY_INIT for Surface Go 3 - Type-Cover - -The touchpad on the Type-Cover of the Surface Go 3 is sometimes not -being initialized properly. Apply USB_QUIRK_DELAY_INIT to fix this -issue. - -More specifically, the device in question is a fairly standard modern -touchpad with pointer and touchpad input modes. During setup, the device -needs to be switched from pointer- to touchpad-mode (which is done in -hid-multitouch) to fully utilize it as intended. Unfortunately, however, -this seems to occasionally fail silently, leaving the device in -pointer-mode. Applying USB_QUIRK_DELAY_INIT seems to fix this. - -Link: https://github.com/linux-surface/linux-surface/issues/1059 -Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: surface-typecover ---- - drivers/usb/core/quirks.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c -index b4783574b8e6..360970620589 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.44.0 - -From bf5167d418b660e321368222505a97d9f1ed68b4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= <verdre@v0yd.nl> -Date: Thu, 5 Nov 2020 13:09:45 +0100 -Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when - suspending - -The Type Cover for Microsoft Surface devices supports a special usb -control request to disable or enable the built-in keyboard backlight. -On Windows, this request happens when putting the device into suspend or -resuming it, without it the backlight of the Type Cover will remain -enabled for some time even though the computer is suspended, which looks -weird to the user. - -So add support for this special usb control request to hid-multitouch, -which is the driver that's handling the Type Cover. - -The reason we have to use a pm_notifier for this instead of the usual -suspend/resume methods is that those won't get called in case the usb -device is already autosuspended. - -Also, if the device is autosuspended, we have to briefly autoresume it -in order to send the request. Doing that should be fine, the usb-core -driver does something similar during suspend inside choose_wakeup(). - -To make sure we don't send that request to every device but only to -devices which support it, add a new quirk -MT_CLS_WIN_8_MS_SURFACE_TYPE_COVER to hid-multitouch. For now this quirk -is only enabled for the usb id of the Surface Pro 2017 Type Cover, which -is where I confirmed that it's working. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 100 ++++++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 3e91e4d6ba6f..45b7884c97f0 100644 ---- a/drivers/hid/hid-multitouch.c -+++ b/drivers/hid/hid-multitouch.c -@@ -34,7 +34,10 @@ - #include <linux/device.h> - #include <linux/hid.h> - #include <linux/module.h> -+#include <linux/pm_runtime.h> - #include <linux/slab.h> -+#include <linux/suspend.h> -+#include <linux/usb.h> - #include <linux/input/mt.h> - #include <linux/jiffies.h> - #include <linux/string.h> -@@ -47,6 +50,7 @@ MODULE_DESCRIPTION("HID multitouch panels"); - MODULE_LICENSE("GPL"); - - #include "hid-ids.h" -+#include "usbhid/usbhid.h" - - /* quirks to control the device */ - #define MT_QUIRK_NOT_SEEN_MEANS_UP BIT(0) -@@ -72,12 +76,15 @@ MODULE_LICENSE("GPL"); - #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) - #define MT_QUIRK_DISABLE_WAKEUP BIT(21) - #define MT_QUIRK_ORIENTATION_INVERT BIT(22) -+#define MT_QUIRK_HAS_TYPE_COVER_BACKLIGHT BIT(23) - - #define MT_INPUTMODE_TOUCHSCREEN 0x02 - #define MT_INPUTMODE_TOUCHPAD 0x03 - - #define MT_BUTTONTYPE_CLICKPAD 0 - -+#define MS_TYPE_COVER_FEATURE_REPORT_USAGE 0xff050086 -+ - enum latency_mode { - HID_LATENCY_NORMAL = 0, - HID_LATENCY_HIGH = 1, -@@ -169,6 +176,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, -@@ -213,6 +222,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 -@@ -397,6 +407,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 -+ }, - { } - }; - -@@ -1721,6 +1741,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; -@@ -1744,6 +1827,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); - -@@ -1782,15 +1868,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) -@@ -1840,6 +1930,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); -@@ -2230,6 +2321,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.44.0 - -From dda4ca6e0248ae5acf3aaf78ee00e613f4e04bad Mon Sep 17 00:00:00 2001 -From: PJungkamp <p.jungkamp@gmail.com> -Date: Fri, 25 Feb 2022 12:04:25 +0100 -Subject: [PATCH] hid/multitouch: Add support for surface pro type cover tablet - switch - -The Surface Pro Type Cover has several non standard HID usages in it's -hid report descriptor. -I noticed that, upon folding the typecover back, a vendor specific range -of 4 32 bit integer hid usages is transmitted. -Only the first byte of the message seems to convey reliable information -about the keyboard state. - -0x22 => Normal (keys enabled) -0x33 => Folded back (keys disabled) -0x53 => Rotated left/right side up (keys disabled) -0x13 => Cover closed (keys disabled) -0x43 => Folded back and Tablet upside down (keys disabled) -This list may not be exhaustive. - -The tablet mode switch will be disabled for a value of 0x22 and enabled -on any other value. - -Patchset: surface-typecover ---- - drivers/hid/hid-multitouch.c | 148 +++++++++++++++++++++++++++++------ - 1 file changed, 122 insertions(+), 26 deletions(-) - -diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c -index 45b7884c97f0..f8978b405aca 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, -@@ -409,6 +412,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 | -@@ -1390,6 +1394,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; -@@ -1417,6 +1424,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); -@@ -1438,6 +1460,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) { -@@ -1445,6 +1468,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; - } -@@ -1454,11 +1490,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; - } - -@@ -1611,6 +1657,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); -@@ -1659,6 +1741,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; -@@ -1741,30 +1830,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); -@@ -1773,8 +1838,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; - } -@@ -1908,13 +1974,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. */ -@@ -1923,12 +2000,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.44.0 +2.45.1 -From aa49dc59b192cc038ca789ac70215d7492f043cb Mon Sep 17 00:00:00 2001 +From 9e0b83c9668c3d0e8e5ce9c254697056940a205d Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sun, 19 Feb 2023 22:12:24 +0100 Subject: [PATCH] PCI: Add quirk to prevent calling shutdown mehtod @@ -7924,10 +10022,10 @@ Patchset: surface-shutdown 3 files changed, 40 insertions(+) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 51ec9e7e784f..40554890d721 100644 +index af2996d0d17ff..3ce0fb61257dc 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c -@@ -507,6 +507,9 @@ static void pci_device_shutdown(struct device *dev) +@@ -505,6 +505,9 @@ static void pci_device_shutdown(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_driver *drv = pci_dev->driver; @@ -7938,10 +10036,10 @@ index 51ec9e7e784f..40554890d721 100644 if (drv && drv->shutdown) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index d797df6e5f3e..c674ee496a0b 100644 +index eff7f5df08e27..d1cb4ff3ebc57 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -6250,3 +6250,39 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev) +@@ -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); @@ -7982,7 +10080,7 @@ index d797df6e5f3e..c674ee496a0b 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 7ab0d13672da..8d8d9225e0db 100644 +index 16493426a04ff..0eb821624056d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -465,6 +465,7 @@ struct pci_dev { @@ -7994,9 +10092,9 @@ index 7ab0d13672da..8d8d9225e0db 100644 atomic_t enable_cnt; /* pci_enable_device has been called */ -- -2.44.0 +2.45.1 -From 36cf5399fd0f16f10f97c21131d29ebda13607f5 Mon Sep 17 00:00:00 2001 +From 739ab84095d8ea8ec8fe05447706c6eb2ffa3f35 Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Sun, 12 Mar 2023 01:41:57 +0100 Subject: [PATCH] platform/surface: gpe: Add support for Surface Pro 9 @@ -8010,7 +10108,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 62fd4004db31..103fc4468262 100644 +index 62fd4004db31a..103fc4468262a 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[] = { @@ -8045,9 +10143,9 @@ index 62fd4004db31..103fc4468262 100644 .ident = "Surface Book 1", .matches = { -- -2.44.0 +2.45.1 -From 526bea529e4befa282fcfd01bbadbed7325faf01 Mon Sep 17 00:00:00 2001 +From 44ed44fe421e484bcf2de223d7e8077302635772 Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdegoede@redhat.com> Date: Sun, 10 Oct 2021 20:56:57 +0200 Subject: [PATCH] ACPI: delay enumeration of devices with a _DEP pointing to an @@ -8107,10 +10205,10 @@ Patchset: cameras 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index e6ed1ba91e5c..b367890b7438 100644 +index d1464324de951..5d865a34dd9db 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c -@@ -2138,6 +2138,9 @@ static acpi_status acpi_bus_check_add_2(acpi_handle handle, u32 lvl_not_used, +@@ -2181,6 +2181,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) { @@ -8121,9 +10219,9 @@ index e6ed1ba91e5c..b367890b7438 100644 * Do not enumerate devices with enumeration_by_parent flag set as * they will be enumerated by their respective parents. -- -2.44.0 +2.45.1 -From d41ef92974135b1c22c2f46cbaba926701e0d4af Mon Sep 17 00:00:00 2001 +From d9d5afcea9880a957d6a8d975a122b4f54ec28c2 Mon Sep 17 00:00:00 2001 From: zouxiaoh <xiaohong.zou@intel.com> Date: Fri, 25 Jun 2021 08:52:59 +0800 Subject: [PATCH] iommu: intel-ipu: use IOMMU passthrough mode for Intel IPUs @@ -8149,10 +10247,10 @@ Patchset: cameras 1 file changed, 30 insertions(+) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 6c01b1aebf27..ceed043464b1 100644 +index 61bc54299a591..a61af0f4e9fce 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c -@@ -45,6 +45,13 @@ +@@ -44,6 +44,13 @@ ((pdev)->vendor == PCI_VENDOR_ID_INTEL && (pdev)->device == 0x34E4) \ ) @@ -8166,23 +10264,23 @@ index 6c01b1aebf27..ceed043464b1 100644 #define IOAPIC_RANGE_START (0xfee00000) #define IOAPIC_RANGE_END (0xfeefffff) #define IOVA_START_ADDR (0x1000) -@@ -154,12 +161,14 @@ EXPORT_SYMBOL_GPL(intel_iommu_enabled); +@@ -227,12 +234,14 @@ int intel_iommu_enabled = 0; + EXPORT_SYMBOL_GPL(intel_iommu_enabled); - static int dmar_map_gfx = 1; static int dmar_map_ipts = 1; +static int dmar_map_ipu = 1; static int intel_iommu_superpage = 1; static int iommu_identity_mapping; static int iommu_skip_te_disable; + static int disable_igfx_iommu; - #define IDENTMAP_GFX 2 #define IDENTMAP_AZALIA 4 +#define IDENTMAP_IPU 8 #define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -2420,6 +2429,9 @@ static int device_def_domain_type(struct device *dev) - if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) +@@ -2409,6 +2418,9 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev)) return IOMMU_DOMAIN_IDENTITY; + if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) @@ -8191,9 +10289,9 @@ index 6c01b1aebf27..ceed043464b1 100644 if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) return IOMMU_DOMAIN_IDENTITY; } -@@ -2729,6 +2741,9 @@ static int __init init_dmars(void) - if (!dmar_map_gfx) - iommu_identity_mapping |= IDENTMAP_GFX; +@@ -2711,6 +2723,9 @@ static int __init init_dmars(void) + iommu_set_root_entry(iommu); + } + if (!dmar_map_ipu) + iommu_identity_mapping |= IDENTMAP_IPU; @@ -8201,8 +10299,8 @@ index 6c01b1aebf27..ceed043464b1 100644 if (!dmar_map_ipts) iommu_identity_mapping |= IDENTMAP_IPTS; -@@ -4909,6 +4924,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - dmar_map_gfx = 0; +@@ -4884,6 +4899,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + disable_igfx_iommu = 1; } +static void quirk_iommu_ipu(struct pci_dev *dev) @@ -8220,7 +10318,7 @@ index 6c01b1aebf27..ceed043464b1 100644 static void quirk_iommu_ipts(struct pci_dev *dev) { if (!IS_IPTS(dev)) -@@ -4956,6 +4983,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4931,6 +4958,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); @@ -8231,9 +10329,9 @@ index 6c01b1aebf27..ceed043464b1 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.44.0 +2.45.1 -From 214600c4c0c3039ba0d0a5e522a2eb162da3857b Mon Sep 17 00:00:00 2001 +From bbf2fb14fae6c6bda12e156ff9d027913ab7860f Mon Sep 17 00:00:00 2001 From: Daniel Scally <djrscally@gmail.com> Date: Sun, 10 Oct 2021 20:57:02 +0200 Subject: [PATCH] platform/x86: int3472: Enable I2c daisy chain @@ -8250,7 +10348,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 1e107fd49f82..e3e1696e7f0e 100644 +index 1e107fd49f828..e3e1696e7f0ee 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) @@ -8268,9 +10366,9 @@ index 1e107fd49f82..e3e1696e7f0e 100644 return 0; -- -2.44.0 +2.45.1 -From f5c4f5e1de99e04416ddffca65246a7769a202e3 Mon Sep 17 00:00:00 2001 +From bc2732708fc2a71f7fe3808aa84cc6eabbdd1285 Mon Sep 17 00:00:00 2001 From: Daniel Scally <dan.scally@ideasonboard.com> Date: Thu, 2 Mar 2023 12:59:39 +0000 Subject: [PATCH] platform/x86: int3472: Remap reset GPIO for INT347E @@ -8292,7 +10390,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 07b302e09340..1d3097bc7e48 100644 +index 07b302e093407..1d3097bc7e487 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 @@ -8323,9 +10421,9 @@ index 07b302e09340..1d3097bc7e48 100644 agpio, func, polarity); if (ret) -- -2.44.0 +2.45.1 -From 216df183e0ad29051b42fcb856d0818a6094f16d Mon Sep 17 00:00:00 2001 +From 0180b848e145642574d2a91175f92050dcec1ec7 Mon Sep 17 00:00:00 2001 From: Daniel Scally <dan.scally@ideasonboard.com> Date: Tue, 21 Mar 2023 13:45:26 +0000 Subject: [PATCH] media: i2c: Clarify that gain is Analogue gain in OV7251 @@ -8340,7 +10438,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 30f61e04ecaf..9c1292ca8552 100644 +index 30f61e04ecaf5..9c1292ca85522 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) @@ -8362,9 +10460,9 @@ index 30f61e04ecaf..9c1292ca8552 100644 V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, -- -2.44.0 +2.45.1 -From 0573bb8c22ed0f0476a2ca6c5df2a7f09c6a1b66 Mon Sep 17 00:00:00 2001 +From 67553f37af4ea73f824108a08666b537c68972e5 Mon Sep 17 00:00:00 2001 From: Daniel Scally <dan.scally@ideasonboard.com> Date: Wed, 22 Mar 2023 11:01:42 +0000 Subject: [PATCH] media: v4l2-core: Acquire privacy led in @@ -8383,7 +10481,7 @@ 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 3ec323bd528b..b55570a0142c 100644 +index 3ec323bd528b1..b55570a0142cb 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) @@ -8398,7 +10496,7 @@ index 3ec323bd528b..b55570a0142c 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 89c7192148df..44eca113e772 100644 +index 89c7192148dfb..44eca113e7727 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) @@ -8413,9 +10511,9 @@ index 89c7192148df..44eca113e772 100644 if (ret < 0) goto out_cleanup; -- -2.44.0 +2.45.1 -From 84d70102a7892f720a11a0b3d313f3932c859798 Mon Sep 17 00:00:00 2001 +From 82dff76b0fc0e6d8fec20339edcb52fcb3eb1fac Mon Sep 17 00:00:00 2001 From: Kate Hsuan <hpa@redhat.com> Date: Tue, 21 Mar 2023 23:37:16 +0800 Subject: [PATCH] platform: x86: int3472: Add MFD cell for tps68470 LED @@ -8431,7 +10529,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 e3e1696e7f0e..423dc555093f 100644 +index e3e1696e7f0ee..423dc555093f7 100644 --- a/drivers/platform/x86/intel/int3472/tps68470.c +++ b/drivers/platform/x86/intel/int3472/tps68470.c @@ -17,7 +17,7 @@ @@ -8454,9 +10552,9 @@ index e3e1696e7f0e..423dc555093f 100644 for (i = 0; i < board_data->n_gpiod_lookups; i++) gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); -- -2.44.0 +2.45.1 -From 183f7e4da9cacc2a0f9cb3549adad9a3c95f1b94 Mon Sep 17 00:00:00 2001 +From ac5b449b3e7da53dfff6ab59dc32d9714eb2f106 Mon Sep 17 00:00:00 2001 From: Kate Hsuan <hpa@redhat.com> Date: Tue, 21 Mar 2023 23:37:17 +0800 Subject: [PATCH] include: mfd: tps68470: Add masks for LEDA and LEDB @@ -8474,7 +10572,7 @@ Patchset: cameras 1 file changed, 5 insertions(+) diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 +index 7807fa329db00..2d2abb25b944f 100644 --- a/include/linux/mfd/tps68470.h +++ b/include/linux/mfd/tps68470.h @@ -34,6 +34,7 @@ @@ -8495,9 +10593,9 @@ index 7807fa329db0..2d2abb25b944 100644 + #endif /* __LINUX_MFD_TPS68470_H */ -- -2.44.0 +2.45.1 -From 0f3811853f436eed853d7d226eb811f65137d03a Mon Sep 17 00:00:00 2001 +From 3bdaa0c3e0b7dfa3b441e7d19d3f08ff3708e354 Mon Sep 17 00:00:00 2001 From: Kate Hsuan <hpa@redhat.com> Date: Tue, 21 Mar 2023 23:37:18 +0800 Subject: [PATCH] leds: tps68470: Add LED control for tps68470 @@ -8520,10 +10618,10 @@ Patchset: cameras create mode 100644 drivers/leds/leds-tps68470.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index d721b254e1e4..1717f94d1491 100644 +index 05e6af88b88cd..c120eb0b5aa8e 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig -@@ -899,6 +899,18 @@ config LEDS_TPS6105X +@@ -909,6 +909,18 @@ config LEDS_TPS6105X It is a single boost converter primarily for white LEDs and audio amplifiers. @@ -8543,7 +10641,7 @@ index d721b254e1e4..1717f94d1491 100644 tristate "LED support for SGI Octane machines" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index ce07dc295ff0..0ebf6a9f9f7f 100644 +index effdfc6f1e951..6ce609b2cdac6 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o @@ -8556,7 +10654,7 @@ index ce07dc295ff0..0ebf6a9f9f7f 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 000000000000..35aeb5db89c8 +index 0000000000000..35aeb5db89c8f --- /dev/null +++ b/drivers/leds/leds-tps68470.c @@ -0,0 +1,185 @@ @@ -8746,431 +10844,9 @@ index 000000000000..35aeb5db89c8 +MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); +MODULE_LICENSE("GPL v2"); -- -2.44.0 - -From 87ebc160cb35a068acfaf59847c84656cb52b1b7 Mon Sep 17 00:00:00 2001 -From: Sakari Ailus <sakari.ailus@linux.intel.com> -Date: Thu, 25 May 2023 14:12:04 +0300 -Subject: [PATCH] media: ipu3-cio2: Further clean up async subdev link creation - -Use v4l2_create_fwnode_links_to_pad() to create links from async -sub-devices to the CSI-2 receiver subdevs. - -Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> -Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> -Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> -Patchset: cameras ---- - drivers/media/pci/intel/ipu3/ipu3-cio2.c | 22 +++++----------------- - 1 file changed, 5 insertions(+), 17 deletions(-) - -diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c -index ed08bf4178f0..83e29c56fe33 100644 ---- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c -+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c -@@ -28,6 +28,7 @@ - #include <media/v4l2-device.h> - #include <media/v4l2-event.h> - #include <media/v4l2-fwnode.h> -+#include <media/v4l2-mc.h> - #include <media/v4l2-ioctl.h> - #include <media/videobuf2-dma-sg.h> - -@@ -1407,7 +1408,6 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, - static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) - { - struct cio2_device *cio2 = to_cio2_device(notifier); -- struct device *dev = &cio2->pci_dev->dev; - struct sensor_async_subdev *s_asd; - struct v4l2_async_connection *asd; - struct cio2_queue *q; -@@ -1417,23 +1417,10 @@ static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) - s_asd = to_sensor_asd(asd); - q = &cio2->queue[s_asd->csi2.port]; - -- ret = media_entity_get_fwnode_pad(&q->sensor->entity, -- s_asd->asd.match.fwnode, -- MEDIA_PAD_FL_SOURCE); -- if (ret < 0) { -- dev_err(dev, "no pad for endpoint %pfw (%d)\n", -- s_asd->asd.match.fwnode, ret); -- return ret; -- } -- -- ret = media_create_pad_link(&q->sensor->entity, ret, -- &q->subdev.entity, CIO2_PAD_SINK, -- 0); -- if (ret) { -- dev_err(dev, "failed to create link for %s (endpoint %pfw, error %d)\n", -- q->sensor->name, s_asd->asd.match.fwnode, ret); -+ ret = v4l2_create_fwnode_links_to_pad(asd->sd, -+ &q->subdev_pads[CIO2_PAD_SINK], 0); -+ if (ret) - return ret; -- } - } - - return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); -@@ -1572,6 +1559,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) - v4l2_subdev_init(subdev, &cio2_subdev_ops); - subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; - subdev->owner = THIS_MODULE; -+ subdev->dev = dev; - snprintf(subdev->name, sizeof(subdev->name), - CIO2_ENTITY_NAME " %td", q - cio2->queue); - subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; --- -2.44.0 - -From a9681c29588d67321733877e11f9588ed9e54861 Mon Sep 17 00:00:00 2001 -From: mojyack <mojyack@gmail.com> -Date: Sat, 3 Feb 2024 12:53:33 +0900 -Subject: [PATCH] media: i2c: Revert DW9719 driver - -Patchset: cameras ---- - drivers/media/i2c/dw9719.c | 199 +++++++++++++++++++++++++------------ - 1 file changed, 137 insertions(+), 62 deletions(-) - -diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c -index c626ed845928..d5f585dabb60 100644 ---- a/drivers/media/i2c/dw9719.c -+++ b/drivers/media/i2c/dw9719.c -@@ -6,13 +6,14 @@ - * https://github.com/ZenfoneArea/android_kernel_asus_zenfone5 - */ - -+#include <asm/unaligned.h> -+ - #include <linux/delay.h> - #include <linux/i2c.h> - #include <linux/pm_runtime.h> - #include <linux/regulator/consumer.h> - #include <linux/types.h> - --#include <media/v4l2-cci.h> - #include <media/v4l2-common.h> - #include <media/v4l2-ctrls.h> - #include <media/v4l2-subdev.h> -@@ -20,31 +21,29 @@ - #define DW9719_MAX_FOCUS_POS 1023 - #define DW9719_CTRL_STEPS 16 - #define DW9719_CTRL_DELAY_US 1000 -+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - --#define DW9719_INFO CCI_REG8(0) -+#define DW9719_INFO 0 - #define DW9719_ID 0xF1 -+#define DW9719_CONTROL 2 -+#define DW9719_VCM_CURRENT 3 - --#define DW9719_CONTROL CCI_REG8(2) --#define DW9719_ENABLE_RINGING 0x02 -- --#define DW9719_VCM_CURRENT CCI_REG16(3) -- --#define DW9719_MODE CCI_REG8(6) --#define DW9719_MODE_SAC_SHIFT 4 --#define DW9719_MODE_SAC3 4 -+#define DW9719_MODE 6 -+#define DW9719_VCM_FREQ 7 - --#define DW9719_VCM_FREQ CCI_REG8(7) -+#define DW9719_MODE_SAC3 0x40 - #define DW9719_DEFAULT_VCM_FREQ 0x60 -+#define DW9719_ENABLE_RINGING 0x02 -+ -+#define NUM_REGULATORS 2 - - #define to_dw9719_device(x) container_of(x, struct dw9719_device, sd) - - struct dw9719_device { -- struct v4l2_subdev sd; - struct device *dev; -- struct regmap *regmap; -- struct regulator *regulator; -- u32 sac_mode; -- u32 vcm_freq; -+ struct i2c_client *client; -+ struct regulator_bulk_data regulators[NUM_REGULATORS]; -+ struct v4l2_subdev sd; - - struct dw9719_v4l2_ctrls { - struct v4l2_ctrl_handler handler; -@@ -52,18 +51,79 @@ struct dw9719_device { - } ctrls; - }; - -+static int dw9719_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -+{ -+ struct i2c_msg msg[2]; -+ u8 buf[2] = { reg }; -+ int ret; -+ -+ msg[0].addr = client->addr; -+ msg[0].flags = 0; -+ msg[0].len = 1; -+ msg[0].buf = buf; -+ -+ msg[1].addr = client->addr; -+ msg[1].flags = I2C_M_RD; -+ msg[1].len = 1; -+ msg[1].buf = &buf[1]; -+ *val = 0; -+ -+ ret = i2c_transfer(client->adapter, msg, 2); -+ if (ret < 0) -+ return ret; -+ -+ *val = buf[1]; -+ -+ return 0; -+} -+ -+static int dw9719_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -+{ -+ struct i2c_msg msg; -+ int ret; -+ -+ u8 buf[2] = { reg, val }; -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = sizeof(buf); -+ msg.buf = buf; -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ -+ return ret < 0 ? ret : 0; -+} -+ -+static int dw9719_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -+{ -+ struct i2c_msg msg; -+ u8 buf[3] = { reg }; -+ int ret; -+ -+ put_unaligned_be16(val, buf + 1); -+ -+ msg.addr = client->addr; -+ msg.flags = 0; -+ msg.len = sizeof(buf); -+ msg.buf = buf; -+ -+ ret = i2c_transfer(client->adapter, &msg, 1); -+ -+ return ret < 0 ? ret : 0; -+} -+ - static int dw9719_detect(struct dw9719_device *dw9719) - { - int ret; -- u64 val; -+ u8 val; - -- ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL); -+ ret = dw9719_i2c_rd8(dw9719->client, DW9719_INFO, &val); - if (ret < 0) - return ret; - - if (val != DW9719_ID) { - dev_err(dw9719->dev, "Failed to detect correct id\n"); -- return -ENXIO; -+ ret = -ENXIO; - } - - return 0; -@@ -71,37 +131,54 @@ static int dw9719_detect(struct dw9719_device *dw9719) - - static int dw9719_power_down(struct dw9719_device *dw9719) - { -- return regulator_disable(dw9719->regulator); -+ return regulator_bulk_disable(NUM_REGULATORS, dw9719->regulators); - } - - static int dw9719_power_up(struct dw9719_device *dw9719) - { - int ret; - -- ret = regulator_enable(dw9719->regulator); -+ ret = regulator_bulk_enable(NUM_REGULATORS, dw9719->regulators); - if (ret) - return ret; - - /* Jiggle SCL pin to wake up device */ -- cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL, 1); - -- /* Need 100us to transit from SHUTDOWN to STANDBY */ -- fsleep(100); -+ /* Need 100us to transit from SHUTDOWN to STANDBY*/ -+ usleep_range(100, 1000); - -- cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret); -- cci_write(dw9719->regmap, DW9719_MODE, -- dw9719->sac_mode << DW9719_MODE_SAC_SHIFT, &ret); -- cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_CONTROL, -+ DW9719_ENABLE_RINGING); -+ if (ret < 0) -+ goto fail_powerdown; - -- if (ret) -- dw9719_power_down(dw9719); -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_MODE, DW9719_MODE_SAC3); -+ if (ret < 0) -+ goto fail_powerdown; -+ -+ ret = dw9719_i2c_wr8(dw9719->client, DW9719_VCM_FREQ, -+ DW9719_DEFAULT_VCM_FREQ); -+ if (ret < 0) -+ goto fail_powerdown; -+ -+ return 0; - -+fail_powerdown: -+ dw9719_power_down(dw9719); - return ret; - } - - static int dw9719_t_focus_abs(struct dw9719_device *dw9719, s32 value) - { -- return cci_write(dw9719->regmap, DW9719_VCM_CURRENT, value, NULL); -+ int ret; -+ -+ value = clamp(value, 0, DW9719_MAX_FOCUS_POS); -+ ret = dw9719_i2c_wr16(dw9719->client, DW9719_VCM_CURRENT, value); -+ if (ret < 0) -+ return ret; -+ -+ return 0; - } - - static int dw9719_set_ctrl(struct v4l2_ctrl *ctrl) -@@ -132,7 +209,7 @@ static const struct v4l2_ctrl_ops dw9719_ctrl_ops = { - .s_ctrl = dw9719_set_ctrl, - }; - --static int dw9719_suspend(struct device *dev) -+static int __maybe_unused dw9719_suspend(struct device *dev) - { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct dw9719_device *dw9719 = to_dw9719_device(sd); -@@ -151,7 +228,7 @@ static int dw9719_suspend(struct device *dev) - return dw9719_power_down(dw9719); - } - --static int dw9719_resume(struct device *dev) -+static int __maybe_unused dw9719_resume(struct device *dev) - { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct dw9719_device *dw9719 = to_dw9719_device(sd); -@@ -201,7 +278,9 @@ static int dw9719_init_controls(struct dw9719_device *dw9719) - const struct v4l2_ctrl_ops *ops = &dw9719_ctrl_ops; - int ret; - -- v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1); -+ ret = v4l2_ctrl_handler_init(&dw9719->ctrls.handler, 1); -+ if (ret) -+ return ret; - - dw9719->ctrls.focus = v4l2_ctrl_new_std(&dw9719->ctrls.handler, ops, - V4L2_CID_FOCUS_ABSOLUTE, 0, -@@ -214,7 +293,8 @@ static int dw9719_init_controls(struct dw9719_device *dw9719) - } - - dw9719->sd.ctrl_handler = &dw9719->ctrls.handler; -- return 0; -+ -+ return ret; - - err_free_handler: - v4l2_ctrl_handler_free(&dw9719->ctrls.handler); -@@ -232,26 +312,24 @@ static int dw9719_probe(struct i2c_client *client) - if (!dw9719) - return -ENOMEM; - -- dw9719->regmap = devm_cci_regmap_init_i2c(client, 8); -- if (IS_ERR(dw9719->regmap)) -- return PTR_ERR(dw9719->regmap); -- -+ dw9719->client = client; - dw9719->dev = &client->dev; -- dw9719->sac_mode = DW9719_MODE_SAC3; -- dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ; - -- /* Optional indication of SAC mode select */ -- device_property_read_u32(&client->dev, "dongwoon,sac-mode", -- &dw9719->sac_mode); -- -- /* Optional indication of VCM frequency */ -- device_property_read_u32(&client->dev, "dongwoon,vcm-freq", -- &dw9719->vcm_freq); -+ dw9719->regulators[0].supply = "vdd"; -+ /* -+ * The DW9719 has only the 1 VDD voltage input, but some PMICs such as -+ * the TPS68470 PMIC have I2C passthrough capability, to disconnect the -+ * sensor's I2C pins from the I2C bus when the sensors VSIO (Sensor-IO) -+ * is off, because some sensors then short these pins to ground; -+ * and the DW9719 might sit behind this passthrough, this it needs to -+ * enable VSIO as that will also enable the I2C passthrough. -+ */ -+ dw9719->regulators[1].supply = "vsio"; - -- dw9719->regulator = devm_regulator_get(&client->dev, "vdd"); -- if (IS_ERR(dw9719->regulator)) -- return dev_err_probe(&client->dev, PTR_ERR(dw9719->regulator), -- "getting regulator\n"); -+ ret = devm_regulator_bulk_get(&client->dev, NUM_REGULATORS, -+ dw9719->regulators); -+ if (ret) -+ return dev_err_probe(&client->dev, ret, "getting regulators\n"); - - v4l2_i2c_subdev_init(&dw9719->sd, client, &dw9719_ops); - dw9719->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; -@@ -312,17 +390,13 @@ static int dw9719_probe(struct i2c_client *client) - static void dw9719_remove(struct i2c_client *client) - { - struct v4l2_subdev *sd = i2c_get_clientdata(client); -- struct dw9719_device *dw9719 = -- container_of(sd, struct dw9719_device, sd); -+ struct dw9719_device *dw9719 = container_of(sd, struct dw9719_device, -+ sd); - -+ pm_runtime_disable(&client->dev); - v4l2_async_unregister_subdev(sd); - v4l2_ctrl_handler_free(&dw9719->ctrls.handler); - media_entity_cleanup(&dw9719->sd.entity); -- -- pm_runtime_disable(&client->dev); -- if (!pm_runtime_status_suspended(&client->dev)) -- dw9719_power_down(dw9719); -- pm_runtime_set_suspended(&client->dev); - } - - static const struct i2c_device_id dw9719_id_table[] = { -@@ -331,13 +405,14 @@ static const struct i2c_device_id dw9719_id_table[] = { - }; - MODULE_DEVICE_TABLE(i2c, dw9719_id_table); - --static DEFINE_RUNTIME_DEV_PM_OPS(dw9719_pm_ops, dw9719_suspend, dw9719_resume, -- NULL); -+static const struct dev_pm_ops dw9719_pm_ops = { -+ SET_RUNTIME_PM_OPS(dw9719_suspend, dw9719_resume, NULL) -+}; - - static struct i2c_driver dw9719_i2c_driver = { - .driver = { - .name = "dw9719", -- .pm = pm_sleep_ptr(&dw9719_pm_ops), -+ .pm = &dw9719_pm_ops, - }, - .probe = dw9719_probe, - .remove = dw9719_remove, --- -2.44.0 +2.45.1 -From c5d6c95fd5cefbd4ba9779fc965bce0a36bdbe5e Mon Sep 17 00:00:00 2001 +From 05501de0dab9bc531918dcf2b8aa7e679760fd7b Mon Sep 17 00:00:00 2001 From: mojyack <mojyack@gmail.com> Date: Sat, 3 Feb 2024 12:59:53 +0900 Subject: [PATCH] media: staging: ipu3-imgu: Fix multiple calls of s_stream on @@ -9184,7 +10860,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 3df58eb3e882..81aff2d5d898 100644 +index 3df58eb3e8822..81aff2d5d8988 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) @@ -9215,9 +10891,41 @@ index 3df58eb3e882..81aff2d5d898 100644 r = imgu_s_stream(imgu, false); if (!r) -- -2.44.0 +2.45.1 + +From c85328d7df3de31a574e42f66192c6a944f48bde Mon Sep 17 00:00:00 2001 +From: mojyack <mojyack@gmail.com> +Date: Tue, 26 Mar 2024 05:55:44 +0900 +Subject: [PATCH] media: i2c: dw9719: fix probe error on surface go 2 + +On surface go 2, sometimes probing dw9719 fails with "dw9719: probe of i2c-INT347A:00-VCM failed with error -121". +The -121(-EREMOTEIO) is came from drivers/i2c/busses/i2c-designware-common.c:575, and indicates the initialize occurs too early. +So just add some delay. +There is no exact reason for this 10000us, but 100us failed. + +Patchset: cameras +--- + drivers/media/i2c/dw9719.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c +index c626ed845928c..0094cfda57ea8 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) + if (ret) + return ret; + ++ /* Wait for device to be acknowledged */ ++ fsleep(10000); ++ + /* Jiggle SCL pin to wake up device */ + cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret); + +-- +2.45.1 -From 302d8dc26283bc10ba22bc549c41292d00125e60 Mon Sep 17 00:00:00 2001 +From e0b584d3054d7c69d2e1b4f2ca54e42b79ee5446 Mon Sep 17 00:00:00 2001 From: Sachi King <nakato@nakato.io> Date: Sat, 29 May 2021 17:47:38 +1000 Subject: [PATCH] ACPI: Add quirk for Surface Laptop 4 AMD missing irq 7 @@ -9240,7 +10948,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 85a3ce2a3666..2c0e04a3a697 100644 +index 4bf82dbd2a6b5..7a8cb090c6568 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -22,6 +22,7 @@ @@ -9251,7 +10959,7 @@ index 85a3ce2a3666..2c0e04a3a697 100644 #include <asm/e820/api.h> #include <asm/irqdomain.h> -@@ -1251,6 +1252,17 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1216,6 +1217,17 @@ static void __init mp_config_acpi_legacy_irqs(void) } } @@ -9269,7 +10977,7 @@ index 85a3ce2a3666..2c0e04a3a697 100644 /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -@@ -1306,6 +1318,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) +@@ -1271,6 +1283,11 @@ static int __init acpi_parse_madt_ioapic_entries(void) acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0, acpi_gbl_FADT.sci_interrupt); @@ -9282,9 +10990,9 @@ index 85a3ce2a3666..2c0e04a3a697 100644 mp_config_acpi_legacy_irqs(); -- -2.44.0 +2.45.1 -From d2a793e4fd47cd1cba2847915e7078671d9e9ea5 Mon Sep 17 00:00:00 2001 +From dafa7b45eecb1e02dc857158566d2fb3087fa71f Mon Sep 17 00:00:00 2001 From: Maximilian Luz <luzmaximilian@gmail.com> Date: Thu, 3 Jun 2021 14:04:26 +0200 Subject: [PATCH] ACPI: Add AMD 13" Surface Laptop 4 model to irq 7 override @@ -9299,10 +11007,10 @@ 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 2c0e04a3a697..b0e1dab3d2ec 100644 +index 7a8cb090c6568..0faafc323e673 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c -@@ -1254,12 +1254,19 @@ static void __init mp_config_acpi_legacy_irqs(void) +@@ -1219,12 +1219,19 @@ static void __init mp_config_acpi_legacy_irqs(void) static const struct dmi_system_id surface_quirk[] __initconst = { { @@ -9324,9 +11032,9 @@ index 2c0e04a3a697..b0e1dab3d2ec 100644 }; -- -2.44.0 +2.45.1 -From 34ad5b493b00c944ed68d2436cad96785fe37a33 Mon Sep 17 00:00:00 2001 +From e3e62473f885786f1b57421f5fed86ac5ba402ac Mon Sep 17 00:00:00 2001 From: "Bart Groeneveld | GPX Solutions B.V" <bart@gpxbv.nl> Date: Mon, 5 Dec 2022 16:08:46 +0100 Subject: [PATCH] acpi: allow usage of acpi_tad on HW-reduced platforms @@ -9349,7 +11057,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 33c3b16af556..900445d06623 100644 +index 1d670dbe4d1dd..71c9e375ca1ca 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, @@ -9386,7 +11094,7 @@ index 33c3b16af556..900445d06623 100644 }; static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -564,13 +571,18 @@ static int acpi_tad_remove(struct platform_device *pdev) +@@ -564,13 +571,18 @@ static void acpi_tad_remove(struct platform_device *pdev) pm_runtime_get_sync(dev); @@ -9407,7 +11115,7 @@ index 33c3b16af556..900445d06623 100644 if (dd->capabilities & ACPI_TAD_DC_WAKE) { acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); -@@ -613,12 +625,6 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -612,12 +624,6 @@ static int acpi_tad_probe(struct platform_device *pdev) goto remove_handler; } @@ -9420,7 +11128,7 @@ index 33c3b16af556..900445d06623 100644 dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); if (!dd) { ret = -ENOMEM; -@@ -649,6 +655,12 @@ static int acpi_tad_probe(struct platform_device *pdev) +@@ -648,6 +654,12 @@ static int acpi_tad_probe(struct platform_device *pdev) if (ret) goto fail; @@ -9434,5 +11142,5 @@ index 33c3b16af556..900445d06623 100644 ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); if (ret) -- -2.44.0 +2.45.1 |