diff options
Diffstat (limited to 'SOURCES/linux-surface.patch')
-rw-r--r-- | SOURCES/linux-surface.patch | 6770 |
1 files changed, 2171 insertions, 4599 deletions
diff --git a/SOURCES/linux-surface.patch b/SOURCES/linux-surface.patch index a805f46..6d81170 100644 --- a/SOURCES/linux-surface.patch +++ b/SOURCES/linux-surface.patch @@ -1,463 +1,294 @@ -From 4eacf265d5adbd67e1f3ee63ba76ebfbc213c8ba 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 - table +From 9916eca4bc0ff2ae5dc36de98b2377e5d839bc41 Mon Sep 17 00:00:00 2001 +From: GloriousEggroll <gloriouseggroll@gmail.com> +Date: Wed, 30 Aug 2023 20:24:03 -0600 +Subject: [PATCH 05/18] linux-surface -On some Surface 3, the DMI table gets corrupted for unknown reasons -and breaks existing DMI matching used for device-specific quirks. - -This commit adds the (broken) DMI data into dmi_system_id tables used -for quirks so that each driver can enable quirks even on the affected -systems. - -On affected systems, DMI data will look like this: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:OEMB - /sys/devices/virtual/dmi/id/board_vendor:OEMB - /sys/devices/virtual/dmi/id/chassis_vendor:OEMB - /sys/devices/virtual/dmi/id/product_name:OEMB - /sys/devices/virtual/dmi/id/sys_vendor:OEMB - -Expected: - $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ - chassis_vendor,product_name,sys_vendor} - /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. - /sys/devices/virtual/dmi/id/board_name:Surface 3 - /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation - /sys/devices/virtual/dmi/id/product_name:Surface 3 - /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation - -Signed-off-by: Tsuchiya Yuto <kitakar@gmail.com> -Patchset: surface3-oemb --- - drivers/platform/surface/surface3-wmi.c | 7 +++++++ - sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ - 3 files changed, 24 insertions(+) + MAINTAINERS | 7 + + arch/x86/kernel/acpi/boot.c | 24 + + drivers/acpi/acpi_tad.c | 35 +- + drivers/acpi/scan.c | 3 + + drivers/bluetooth/btusb.c | 15 + + drivers/hid/Kconfig | 4 + + drivers/hid/Makefile | 3 + + drivers/hid/hid-multitouch.c | 196 ++++++- + drivers/hid/ipts/Kconfig | 14 + + drivers/hid/ipts/Makefile | 16 + + drivers/hid/ipts/cmd.c | 61 ++ + drivers/hid/ipts/cmd.h | 60 ++ + drivers/hid/ipts/context.h | 52 ++ + drivers/hid/ipts/control.c | 486 ++++++++++++++++ + drivers/hid/ipts/control.h | 126 +++++ + drivers/hid/ipts/desc.h | 80 +++ + drivers/hid/ipts/eds1.c | 103 ++++ + drivers/hid/ipts/eds1.h | 35 ++ + drivers/hid/ipts/eds2.c | 144 +++++ + drivers/hid/ipts/eds2.h | 35 ++ + drivers/hid/ipts/hid.c | 225 ++++++++ + drivers/hid/ipts/hid.h | 24 + + drivers/hid/ipts/main.c | 126 +++++ + drivers/hid/ipts/mei.c | 188 ++++++ + drivers/hid/ipts/mei.h | 66 +++ + drivers/hid/ipts/receiver.c | 250 ++++++++ + drivers/hid/ipts/receiver.h | 16 + + drivers/hid/ipts/resources.c | 131 +++++ + drivers/hid/ipts/resources.h | 41 ++ + drivers/hid/ipts/spec-data.h | 100 ++++ + drivers/hid/ipts/spec-device.h | 290 ++++++++++ + drivers/hid/ipts/spec-hid.h | 34 ++ + drivers/hid/ipts/thread.c | 84 +++ + drivers/hid/ipts/thread.h | 59 ++ + drivers/hid/ithc/Kbuild | 6 + + drivers/hid/ithc/Kconfig | 12 + + drivers/hid/ithc/ithc-debug.c | 96 ++++ + drivers/hid/ithc/ithc-dma.c | 258 +++++++++ + drivers/hid/ithc/ithc-dma.h | 67 +++ + drivers/hid/ithc/ithc-main.c | 534 ++++++++++++++++++ + drivers/hid/ithc/ithc-regs.c | 64 +++ + drivers/hid/ithc/ithc-regs.h | 186 ++++++ + drivers/hid/ithc/ithc.h | 60 ++ + drivers/i2c/i2c-core-acpi.c | 35 ++ + drivers/input/misc/soc_button_array.c | 33 +- + drivers/iommu/intel/iommu.c | 54 ++ + drivers/iommu/intel/irq_remapping.c | 16 + + drivers/leds/Kconfig | 12 + + drivers/leds/Makefile | 1 + + drivers/leds/leds-tps68470.c | 185 ++++++ + drivers/media/i2c/Kconfig | 11 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/dw9719.c | 425 ++++++++++++++ + drivers/media/i2c/ov7251.c | 4 +- + drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 52 +- + drivers/media/v4l2-core/v4l2-async.c | 4 + + drivers/media/v4l2-core/v4l2-fwnode.c | 4 - + drivers/misc/mei/hw-me-regs.h | 1 + + drivers/misc/mei/pci-me.c | 1 + + drivers/net/wireless/ath/ath10k/core.c | 58 ++ + drivers/net/wireless/marvell/mwifiex/pcie.c | 19 + + .../wireless/marvell/mwifiex/pcie_quirks.c | 37 +- + .../wireless/marvell/mwifiex/pcie_quirks.h | 2 + + drivers/pci/pci-driver.c | 3 + + drivers/pci/quirks.c | 36 ++ + drivers/platform/surface/Kconfig | 7 + + drivers/platform/surface/Makefile | 1 + + drivers/platform/surface/surface3-wmi.c | 7 + + drivers/platform/surface/surface_gpe.c | 17 + + .../surface/surfacebook1_dgpu_switch.c | 162 ++++++ + drivers/platform/surface/surfacepro3_button.c | 30 +- + drivers/platform/x86/intel/int3472/discrete.c | 14 + + drivers/platform/x86/intel/int3472/tps68470.c | 12 +- + drivers/usb/core/quirks.c | 3 + + include/linux/mfd/tps68470.h | 5 + + include/linux/pci.h | 1 + + sound/soc/codecs/rt5645.c | 9 + + .../intel/common/soc-acpi-intel-cht-match.c | 8 + + 78 files changed, 5579 insertions(+), 107 deletions(-) + create mode 100644 drivers/hid/ipts/Kconfig + create mode 100644 drivers/hid/ipts/Makefile + create mode 100644 drivers/hid/ipts/cmd.c + create mode 100644 drivers/hid/ipts/cmd.h + create mode 100644 drivers/hid/ipts/context.h + create mode 100644 drivers/hid/ipts/control.c + create mode 100644 drivers/hid/ipts/control.h + create mode 100644 drivers/hid/ipts/desc.h + create mode 100644 drivers/hid/ipts/eds1.c + create mode 100644 drivers/hid/ipts/eds1.h + create mode 100644 drivers/hid/ipts/eds2.c + create mode 100644 drivers/hid/ipts/eds2.h + create mode 100644 drivers/hid/ipts/hid.c + create mode 100644 drivers/hid/ipts/hid.h + create mode 100644 drivers/hid/ipts/main.c + create mode 100644 drivers/hid/ipts/mei.c + create mode 100644 drivers/hid/ipts/mei.h + create mode 100644 drivers/hid/ipts/receiver.c + create mode 100644 drivers/hid/ipts/receiver.h + create mode 100644 drivers/hid/ipts/resources.c + create mode 100644 drivers/hid/ipts/resources.h + create mode 100644 drivers/hid/ipts/spec-data.h + create mode 100644 drivers/hid/ipts/spec-device.h + create mode 100644 drivers/hid/ipts/spec-hid.h + create mode 100644 drivers/hid/ipts/thread.c + create mode 100644 drivers/hid/ipts/thread.h + create mode 100644 drivers/hid/ithc/Kbuild + create mode 100644 drivers/hid/ithc/Kconfig + create mode 100644 drivers/hid/ithc/ithc-debug.c + create mode 100644 drivers/hid/ithc/ithc-dma.c + create mode 100644 drivers/hid/ithc/ithc-dma.h + create mode 100644 drivers/hid/ithc/ithc-main.c + create mode 100644 drivers/hid/ithc/ithc-regs.c + create mode 100644 drivers/hid/ithc/ithc-regs.h + create mode 100644 drivers/hid/ithc/ithc.h + create mode 100644 drivers/leds/leds-tps68470.c + create mode 100644 drivers/media/i2c/dw9719.c + create mode 100644 drivers/platform/surface/surfacebook1_dgpu_switch.c -diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c -index ca4602bcc7de..490b9731068a 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[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, -+ { -+ .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ }, - #endif - { } - }; -diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 7c7cbb6362ea..81a8ff40e86e 100644 ---- a/sound/soc/codecs/rt5645.c -+++ b/sound/soc/codecs/rt5645.c -@@ -3717,6 +3717,15 @@ static const struct dmi_system_id dmi_platform_data[] = { - }, - .driver_data = (void *)&intel_braswell_platform_data, - }, +diff --git a/MAINTAINERS b/MAINTAINERS +index 4cc6bf79f..439cf523b 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -6251,6 +6251,13 @@ T: git git://linuxtv.org/media_tree.git + F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml + F: drivers/media/i2c/dw9714.c + ++DONGWOON DW9719 LENS VOICE COIL DRIVER ++M: Daniel Scally <djrscally@gmail.com> ++L: linux-media@vger.kernel.org ++S: Maintained ++T: git git://linuxtv.org/media_tree.git ++F: drivers/media/i2c/dw9719.c ++ + DONGWOON DW9768 LENS VOICE COIL DRIVER + M: Dongchun Zhu <dongchun.zhu@mediatek.com> + L: linux-media@vger.kernel.org +diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c +index 53369c577..a7d40015e 100644 +--- a/arch/x86/kernel/acpi/boot.c ++++ b/arch/x86/kernel/acpi/boot.c +@@ -22,6 +22,7 @@ + #include <linux/efi-bgrt.h> + #include <linux/serial_core.h> + #include <linux/pgtable.h> ++#include <linux/dmi.h> + + #include <asm/e820/api.h> + #include <asm/irqdomain.h> +@@ -1256,6 +1257,24 @@ static void __init mp_config_acpi_legacy_irqs(void) + } + } + ++static const struct dmi_system_id surface_quirk[] __initconst = { + { -+ .ident = "Microsoft Surface 3", ++ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", + .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") + }, -+ .driver_data = (void *)&intel_braswell_platform_data, + }, - { - /* - * 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 cdcbf04b8832..958305779b12 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[] = { - DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), - }, - }, + { -+ .callback = cht_surface_quirk_cb, ++ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", + .matches = { -+ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") + }, + }, - { } - }; - --- -2.41.0 - -From 7d293837789acaa3b865552ea304cf3fa3cc3b1b 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 - devices - -The most recent firmware of the 88W8897 card reports a hardcoded LTR -value to the system during initialization, probably as an (unsuccessful) -attempt of the developers to fix firmware crashes. This LTR value -prevents most of the Microsoft Surface devices from entering deep -powersaving states (either platform C-State 10 or S0ix state), because -the exit latency of that state would be higher than what the card can -tolerate. - -Turns out the card works just the same (including the firmware crashes) -no matter if that hardcoded LTR value is reported or not, so it's kind -of useless and only prevents us from saving power. - -To get rid of those hardcoded LTR reports, it's possible to reset the -PCI bridge device after initializing the cards firmware. I'm not exactly -sure why that works, maybe the power management subsystem of the PCH -resets its stored LTR values when doing a function level reset of the -bridge device. Doing the reset once after starting the wifi firmware -works very well, probably because the firmware only reports that LTR -value a single time during firmware startup. - -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 12 +++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 26 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 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 9a698a16a8f3..14687342bc81 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -1762,9 +1762,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) - static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; -+ struct pci_dev *pdev = card->dev; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; - int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; ++ {} ++}; ++ + /* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error +@@ -1311,6 +1330,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); -+ /* Trigger a function level reset of the PCI bridge device, this makes -+ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value -+ * that prevents the system from entering package C10 and S0ix powersaving -+ * states. -+ * We need to do it here because it must happen after firmware -+ * initialization and this function is called after that is done. -+ */ -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ pci_reset_function(parent_pdev); ++ if (dmi_check_system(surface_quirk)) { ++ pr_warn("Surface hack: Override irq 7\n"); ++ mp_override_legacy_irq(7, 3, 3, 7); ++ } + - /* Write the RX ring read pointer in to reg->rx_rdptr */ - if (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 ---- 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[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5", -@@ -22,7 +23,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -31,7 +33,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Pro 6", -@@ -39,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 1", -@@ -47,7 +51,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Book 2", -@@ -55,7 +60,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 1", -@@ -63,7 +69,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - { - .ident = "Surface Laptop 2", -@@ -71,7 +78,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, -- .driver_data = (void *)QUIRK_FW_RST_D3COLD, -+ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -+ QUIRK_DO_FLR_ON_BRIDGE), - }, - {} - }; -@@ -89,6 +97,8 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "no quirks enabled\n"); - if (card->quirks & QUIRK_FW_RST_D3COLD) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) -+ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); - } + /* Fill in identity legacy mappings where no override */ + mp_config_acpi_legacy_irqs(); - 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 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -4,6 +4,7 @@ - #include "pcie.h" +diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c +index e9b8e8305..944276934 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, - #define QUIRK_FW_RST_D3COLD BIT(0) -+#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) + static DEVICE_ATTR_RO(caps); - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.41.0 - -From 9a575242ccba531c0215b7653b3e557569828fe6 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+ - -Currently, mwifiex fw will crash after suspend on recent kernel series. -On Windows, it seems that the root port of wifi will never enter D3 state -(stay on D0 state). And on Linux, disabling the D3 state for the -bridge fixes fw crashing after suspend. - -This commit disables the D3 state of root port on driver initialization -and fixes fw crashing after suspend. - -Signed-off-by: Tsuchiya Yuto <kitakar@gmail.com> -Patchset: mwifiex ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ - .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ - .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + - 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 14687342bc81..5e1a341f63df 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -368,6 +368,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) ++static struct attribute *acpi_tad_attrs[] = { ++ &dev_attr_caps.attr, ++ NULL, ++}; ++static const struct attribute_group acpi_tad_attr_group = { ++ .attrs = acpi_tad_attrs, ++}; ++ + static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; +@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -@@ -409,6 +410,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } + static DEVICE_ATTR_RW(ac_status); -+ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing -+ * after suspend -+ */ -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ parent_pdev->bridge_d3 = false; +-static struct attribute *acpi_tad_attrs[] = { +- &dev_attr_caps.attr, ++static struct attribute *acpi_tad_ac_attrs[] = { + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, + NULL, + }; +-static const struct attribute_group acpi_tad_attr_group = { +- .attrs = acpi_tad_attrs, ++static const struct attribute_group acpi_tad_ac_attr_group = { ++ .attrs = acpi_tad_ac_attrs, + }; + + static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, +@@ -563,13 +570,18 @@ static int acpi_tad_remove(struct platform_device *pdev) + + pm_runtime_get_sync(dev); + ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) ++ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); + - return 0; - } + if (dd->capabilities & ACPI_TAD_DC_WAKE) + sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -index f46b06f8d643..99b024ecbade 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -14,7 +14,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5", -@@ -24,7 +25,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 5 (LTE)", -@@ -34,7 +36,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Pro 6", -@@ -43,7 +46,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 1", -@@ -52,7 +56,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Book 2", -@@ -61,7 +66,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 1", -@@ -70,7 +76,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - { - .ident = "Surface Laptop 2", -@@ -79,7 +86,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), - }, - .driver_data = (void *)(QUIRK_FW_RST_D3COLD | -- QUIRK_DO_FLR_ON_BRIDGE), -+ QUIRK_DO_FLR_ON_BRIDGE | -+ QUIRK_NO_BRIDGE_D3), - }, - {} - }; -@@ -99,6 +107,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) - dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); - if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) - dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); -+ if (card->quirks & QUIRK_NO_BRIDGE_D3) -+ dev_info(&pdev->dev, -+ "quirk no_brigde_d3 enabled\n"); - } + sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - 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 ---- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -+++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -5,6 +5,7 @@ +- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); +- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ if (dd->capabilities & ACPI_TAD_AC_WAKE) { ++ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); ++ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); ++ } + 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); +@@ -604,11 +616,6 @@ static int acpi_tad_probe(struct platform_device *pdev) + return -ENODEV; + } - #define QUIRK_FW_RST_D3COLD BIT(0) - #define QUIRK_DO_FLR_ON_BRIDGE BIT(1) -+#define QUIRK_NO_BRIDGE_D3 BIT(2) +- if (!acpi_has_method(handle, "_PRW")) { +- dev_info(dev, "Missing _PRW\n"); +- return -ENODEV; +- } +- + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; +@@ -637,6 +644,12 @@ static int acpi_tad_probe(struct platform_device *pdev) + if (ret) + goto fail; - void mwifiex_initialize_quirks(struct pcie_service_card *card); - int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); --- -2.41.0 - -From 8d69786e9b9f6879acff05bd3a8821f6dd0d85f9 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 - 88W8897 - -The Marvell 88W8897 combined wifi and bluetooth card (pcie+usb version) -is used in a lot of Microsoft Surface devices, and all those devices -suffer from very low 2.4GHz wifi connection speeds while bluetooth is -enabled. The reason for that is that the default passive scanning -interval for Bluetooth Low Energy devices is quite high in Linux -(interval of 60 msec and scan window of 30 msec, see hci_core.c), and -the Marvell chip is known for its bad bt+wifi coexisting performance. - -So decrease that passive scan interval and make the scan window shorter -on this particular device to allow for spending more time transmitting -wifi signals: The new scan interval is 250 msec (0x190 * 0.625 msec) and -the new scan window is 6.25 msec (0xa * 0,625 msec). - -This change has a very large impact on the 2.4GHz wifi speeds and gets -it up to performance comparable with the Windows driver, which seems to -apply a similar quirk. - -The interval and window length were tested and found to work very well -with a lot of Bluetooth Low Energy devices, including the Surface Pen, a -Bluetooth Speaker and two modern Bluetooth headphones. All devices were -discovered immediately after turning them on. Even lower values were -also tested, but they introduced longer delays until devices get -discovered. - -Patchset: mwifiex ---- - drivers/bluetooth/btusb.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - ++ if (caps & ACPI_TAD_AC_WAKE) { ++ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ if (ret) ++ goto fail; ++ } ++ + if (caps & ACPI_TAD_DC_WAKE) { + ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); + if (ret) +diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c +index 7e9de6e3e..50ceddfe7 100644 +--- a/drivers/acpi/scan.c ++++ b/drivers/acpi/scan.c +@@ -2114,6 +2114,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) + { ++ if (!acpi_dev_ready_for_enumeration(device)) ++ return; ++ + /* + * Do not enumerate devices with enumeration_by_parent flag set as + * they will be enumerated by their respective parents. diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c -index 2a8e2bb038f5..91d15e7c2898 100644 +index 764d176e9..cd6ee1f0f 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -65,6 +65,7 @@ static struct usb_driver btusb_driver; @@ -476,7 +307,7 @@ index 2a8e2bb038f5..91d15e7c2898 100644 /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, -@@ -4296,6 +4298,19 @@ static int btusb_probe(struct usb_interface *intf, +@@ -4302,6 +4304,19 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_MARVELL) hdev->set_bdaddr = btusb_set_bdaddr_marvell; @@ -496,350 +327,400 @@ index 2a8e2bb038f5..91d15e7c2898 100644 if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) && (id->driver_info & BTUSB_MEDIATEK)) { hdev->setup = btusb_mtk_setup; --- -2.41.0 - -From 07ef6257248704323077589c80c00ee99972cbb5 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 - -Some Surface devices, specifically the Surface Go and AMD version of the -Surface Laptop 3 (wich both come with QCA6174 WiFi chips), work better -with a different board file, as it seems that the firmeware included -upstream is buggy. - -As it is generally not a good idea to randomly overwrite files, let -alone doing so via packages, we add module parameters to override those -file names in the driver. This allows us to package/deploy the override -via a modprobe.d config. - -Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: ath10k ---- - drivers/net/wireless/ath/ath10k/core.c | 58 ++++++++++++++++++++++++++ - 1 file changed, 58 insertions(+) - -diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 5eb131ab916f..67f074a126d1 100644 ---- a/drivers/net/wireless/ath/ath10k/core.c -+++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -38,6 +38,9 @@ static bool fw_diag_log; - /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ - unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index e11c1c803..0b58bd30a 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -1334,4 +1334,8 @@ source "drivers/hid/amd-sfh-hid/Kconfig" -+static char *override_board = ""; -+static char *override_board2 = ""; + source "drivers/hid/surface-hid/Kconfig" + ++source "drivers/hid/ipts/Kconfig" + - unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | - BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); ++source "drivers/hid/ithc/Kconfig" ++ + endif # HID_SUPPORT +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index 7a9e16015..656a0783c 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -168,3 +168,6 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ -@@ -50,6 +53,9 @@ module_param(fw_diag_log, bool, 0644); - module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); - module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ ++ ++obj-$(CONFIG_HID_IPTS) += ipts/ ++obj-$(CONFIG_HID_ITHC) += ithc/ +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index e31be0cb8..508a250ff 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"); -+module_param(override_board, charp, 0644); -+module_param(override_board2, charp, 0644); + #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,18 @@ 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_QUIRK_HAS_TYPE_COVER_TABLET_MODE_SWITCH BIT(24) + + #define MT_INPUTMODE_TOUCHSCREEN 0x02 + #define MT_INPUTMODE_TOUCHPAD 0x03 + + #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 + - MODULE_PARM_DESC(debug_mask, "Debugging mask"); - MODULE_PARM_DESC(uart_print, "Uart target debugging"); - MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); -@@ -59,6 +65,9 @@ MODULE_PARM_DESC(frame_mode, - MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); - MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + enum latency_mode { + HID_LATENCY_NORMAL = 0, + HID_LATENCY_HIGH = 1, +@@ -169,6 +179,8 @@ struct mt_device { -+MODULE_PARM_DESC(override_board, "Override for board.bin file"); -+MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); + struct list_head applications; + struct list_head reports; + - static const struct ath10k_hw_params ath10k_hw_params_list[] = { - { - .id = QCA988X_HW_2_0_VERSION, -@@ -911,6 +920,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) ++ struct notifier_block pm_notifier; + }; + + static void mt_post_parse_default_settings(struct mt_device *td, +@@ -213,6 +225,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 +410,17 @@ 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_HAS_TYPE_COVER_TABLET_MODE_SWITCH | ++ 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 ++ }, + { } + }; + +@@ -1370,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; +@@ -1397,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); +@@ -1418,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) { +@@ -1425,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; } +@@ -1434,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; -+static const char *ath10k_override_board_fw_file(struct ath10k *ar, -+ const char *file) + 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; + } + +@@ -1591,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) +{ -+ if (strcmp(file, "board.bin") == 0) { -+ if (strcmp(override_board, "") == 0) -+ return file; ++ struct hid_report *rep; ++ struct hid_field *cur_field; ++ int i, j; + -+ if (strcmp(override_board, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); -+ return NULL; ++ 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; ++} + -+ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", -+ override_board); ++static void request_type_cover_tablet_mode_switch(struct hid_device *hdev) ++{ ++ struct hid_field *field; + -+ return override_board; ++ 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"); + } ++} + -+ if (strcmp(file, "board-2.bin") == 0) { -+ if (strcmp(override_board2, "") == 0) -+ return file; -+ -+ if (strcmp(override_board2, "none") == 0) { -+ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); -+ return NULL; + static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) + { + struct mt_device *td = hid_get_drvdata(hdev); +@@ -1640,6 +1742,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; +@@ -1728,6 +1837,46 @@ static void mt_expired_timeout(struct timer_list *t) + clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags); + } + ++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; + -+ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", -+ override_board2); ++ /* Wake up the device in case it's already suspended */ ++ pm_runtime_get_sync(&udev->dev); + -+ return override_board2; ++ 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; + } + -+ return file; ++ 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 const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - const char *dir, - const char *file) -@@ -925,6 +970,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, - if (dir == NULL) - dir = "."; - -+ /* HACK: Override board.bin and board-2.bin files if specified. -+ * -+ * Some Surface devices perform better with a different board -+ * configuration. To this end, one would need to replace the board.bin -+ * file with the modified config and remove the board-2.bin file. -+ * Unfortunately, that's not a solution that we can easily package. So -+ * we add module options to perform these overrides here. -+ */ ++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; + -+ file = ath10k_override_board_fw_file(ar, file); -+ if (!file) -+ return ERR_PTR(-ENOENT); ++ 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); ++ } + - snprintf(filename, sizeof(filename), "%s/%s", dir, file); - ret = firmware_request_nowarn(&fw, filename, ar->dev); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", --- -2.41.0 - -From 4b251599b09f01035083eabe39b464553b368da9 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] misc: mei: Add missing IPTS device IDs - -Patchset: ipts ---- - drivers/misc/mei/hw-me-regs.h | 1 + - drivers/misc/mei/pci-me.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index bdc65d50b945..08723c01d727 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -92,6 +92,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ - #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - - #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 676d566f38dd..6b37dd1f8b2a 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[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, ++ return NOTIFY_DONE; ++} ++ + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + { + int ret, i; +@@ -1751,6 +1900,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); - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, --- -2.41.0 - -From 36d43ffc88a890636dacf53adcbdf5e844a71b46 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: ipts: use IOMMU passthrough mode for IPTS - -Adds a quirk so that IOMMU uses passthrough mode for the IPTS device. -Otherwise, when IOMMU is enabled, IPTS produces DMAR errors like: - -DMAR: [DMA Read NO_PASID] Request device [00:16.4] fault addr -0x104ea3000 [fault reason 0x06] PTE Read access is not set - -This is very similar to the bug described at: -https://bugs.launchpad.net/bugs/1958004 - -Fixed with the following patch which this patch basically copies: -https://launchpadlibrarian.net/586396847/43255ca.diff -Patchset: ipts ---- - drivers/iommu/intel/iommu.c | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index b871a6afd803..0d4542b7365d 100644 ---- a/drivers/iommu/intel/iommu.c -+++ b/drivers/iommu/intel/iommu.c -@@ -37,6 +37,8 @@ - #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) - #define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB) - #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) -+#define IS_IPTS(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ -+ ((pdev)->device == 0x9d3e)) - #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) ++ td->pm_notifier.notifier_call = mt_pm_notifier; ++ register_pm_notifier(&td->pm_notifier); ++ + INIT_LIST_HEAD(&td->applications); + INIT_LIST_HEAD(&td->reports); - #define IOAPIC_RANGE_START (0xfee00000) -@@ -287,12 +289,14 @@ int intel_iommu_enabled = 0; - EXPORT_SYMBOL_GPL(intel_iommu_enabled); +@@ -1789,15 +1941,19 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + timer_setup(&td->release_timer, mt_expired_timeout, 0); - 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; + ret = hid_parse(hdev); +- if (ret != 0) ++ if (ret != 0) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } - #define IDENTMAP_GFX 2 - #define IDENTMAP_AZALIA 4 -+#define IDENTMAP_IPTS 16 + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); - const struct iommu_ops intel_iommu_ops; + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); +- if (ret) ++ if (ret) { ++ unregister_pm_notifier(&td->pm_notifier); + return ret; ++ } -@@ -2560,6 +2564,9 @@ static int device_def_domain_type(struct device *dev) + ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); + if (ret) +@@ -1826,13 +1982,24 @@ static int mt_suspend(struct hid_device *hdev, pm_message_t state) - if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) - return IOMMU_DOMAIN_IDENTITY; + static int mt_reset_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); + -+ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) -+ return IOMMU_DOMAIN_IDENTITY; - } - - return 0; -@@ -2867,6 +2874,9 @@ static int __init init_dmars(void) - if (!dmar_map_gfx) - iommu_identity_mapping |= IDENTMAP_GFX; - -+ if (!dmar_map_ipts) -+ iommu_identity_mapping |= IDENTMAP_IPTS; + mt_release_contacts(hdev); + mt_set_modes(hdev, HID_LATENCY_NORMAL, true, true); + - check_tylersburg_isoch(); - - ret = si_domain_init(hw_pass_through); -@@ -4778,6 +4788,17 @@ static void quirk_iommu_igfx(struct pci_dev *dev) - dmar_map_gfx = 0; ++ /* 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 void quirk_iommu_ipts(struct pci_dev *dev) -+{ -+ if (!IS_IPTS(dev)) -+ return; -+ -+ if (risky_device(dev)) -+ return; + static int mt_resume(struct hid_device *hdev) + { ++ struct mt_device *td = hid_get_drvdata(hdev); + -+ pci_info(dev, "Passthrough IOMMU for IPTS\n"); -+ dmar_map_ipts = 0; -+} - /* 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); -@@ -4813,6 +4834,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); + /* 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. */ +@@ -1841,6 +2008,10 @@ static int mt_resume(struct hid_device *hdev) -+/* disable IPTS dmar support */ -+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + 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); + - static void quirk_iommu_rwbf(struct pci_dev *dev) + return 0; + } + #endif +@@ -1848,7 +2019,23 @@ static int mt_resume(struct hid_device *hdev) + static void mt_remove(struct hid_device *hdev) { - if (risky_device(dev)) --- -2.41.0 - -From dcc74801efc9dc7f1ba8197d13d78f60f5b7e0f4 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 - -Based on linux-surface/intel-precise-touch@8abe268 - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ipts ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 2 + - drivers/hid/ipts/Kconfig | 14 + - drivers/hid/ipts/Makefile | 14 + - drivers/hid/ipts/cmd.c | 62 +++++ - drivers/hid/ipts/cmd.h | 61 ++++ - drivers/hid/ipts/context.h | 51 ++++ - drivers/hid/ipts/control.c | 495 +++++++++++++++++++++++++++++++++ - drivers/hid/ipts/control.h | 127 +++++++++ - drivers/hid/ipts/desc.h | 81 ++++++ - drivers/hid/ipts/hid.c | 348 +++++++++++++++++++++++ - drivers/hid/ipts/hid.h | 22 ++ - drivers/hid/ipts/main.c | 127 +++++++++ - drivers/hid/ipts/mei.c | 189 +++++++++++++ - drivers/hid/ipts/mei.h | 67 +++++ - drivers/hid/ipts/receiver.c | 249 +++++++++++++++++ - drivers/hid/ipts/receiver.h | 17 ++ - drivers/hid/ipts/resources.c | 108 +++++++ - drivers/hid/ipts/resources.h | 39 +++ - drivers/hid/ipts/spec-data.h | 100 +++++++ - drivers/hid/ipts/spec-device.h | 285 +++++++++++++++++++ - drivers/hid/ipts/spec-hid.h | 35 +++ - drivers/hid/ipts/thread.c | 85 ++++++ - drivers/hid/ipts/thread.h | 60 ++++ - 24 files changed, 2640 insertions(+) - create mode 100644 drivers/hid/ipts/Kconfig - create mode 100644 drivers/hid/ipts/Makefile - create mode 100644 drivers/hid/ipts/cmd.c - create mode 100644 drivers/hid/ipts/cmd.h - create mode 100644 drivers/hid/ipts/context.h - create mode 100644 drivers/hid/ipts/control.c - create mode 100644 drivers/hid/ipts/control.h - create mode 100644 drivers/hid/ipts/desc.h - create mode 100644 drivers/hid/ipts/hid.c - create mode 100644 drivers/hid/ipts/hid.h - create mode 100644 drivers/hid/ipts/main.c - create mode 100644 drivers/hid/ipts/mei.c - create mode 100644 drivers/hid/ipts/mei.h - create mode 100644 drivers/hid/ipts/receiver.c - create mode 100644 drivers/hid/ipts/receiver.h - create mode 100644 drivers/hid/ipts/resources.c - create mode 100644 drivers/hid/ipts/resources.h - create mode 100644 drivers/hid/ipts/spec-data.h - create mode 100644 drivers/hid/ipts/spec-device.h - create mode 100644 drivers/hid/ipts/spec-hid.h - create mode 100644 drivers/hid/ipts/thread.c - create mode 100644 drivers/hid/ipts/thread.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 4ce012f83253..7945cb57f531 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1316,4 +1316,6 @@ source "drivers/hid/amd-sfh-hid/Kconfig" - - source "drivers/hid/surface-hid/Kconfig" + struct mt_device *td = hid_get_drvdata(hdev); ++ struct hid_field *field; ++ struct input_dev *input; -+source "drivers/hid/ipts/Kconfig" ++ /* 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"); ++ } ++ } + - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 5d37cacbde33..285e12d95b0e 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -167,3 +167,5 @@ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ - obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ ++ unregister_pm_notifier(&td->pm_notifier); + del_timer_sync(&td->release_timer); - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ + sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); +@@ -2226,6 +2413,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) }, + -+obj-$(CONFIG_HID_IPTS) += ipts/ + /* Google MT devices */ + { .driver_data = MT_CLS_GOOGLE, + HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_GOOGLE, diff --git a/drivers/hid/ipts/Kconfig b/drivers/hid/ipts/Kconfig new file mode 100644 -index 000000000000..297401bd388d +index 000000000..297401bd3 --- /dev/null +++ b/drivers/hid/ipts/Kconfig @@ -0,0 +1,14 @@ @@ -859,10 +740,10 @@ 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..0fe655bccdc0 +index 000000000..883896f68 --- /dev/null +++ b/drivers/hid/ipts/Makefile -@@ -0,0 +1,14 @@ +@@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile for the IPTS touchscreen driver @@ -871,6 +752,8 @@ index 000000000000..0fe655bccdc0 +obj-$(CONFIG_HID_IPTS) += ipts.o +ipts-objs := cmd.o +ipts-objs += control.o ++ipts-objs += eds1.o ++ipts-objs += eds2.o +ipts-objs += hid.o +ipts-objs += main.o +ipts-objs += mei.o @@ -879,13 +762,12 @@ index 000000000000..0fe655bccdc0 +ipts-objs += thread.o diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c new file mode 100644 -index 000000000000..7fd69271ccd5 +index 000000000..63a4934bb --- /dev/null +++ b/drivers/hid/ipts/cmd.c -@@ -0,0 +1,62 @@ +@@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -947,13 +829,12 @@ index 000000000000..7fd69271ccd5 +} diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h new file mode 100644 -index 000000000000..924758ffee67 +index 000000000..2b4079075 --- /dev/null +++ b/drivers/hid/ipts/cmd.h -@@ -0,0 +1,61 @@ +@@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -972,7 +853,7 @@ index 000000000000..924758ffee67 + */ +#define IPTS_CMD_DEFAULT_TIMEOUT 1000 + -+/* ++/** + * ipts_cmd_recv_timeout() - Receives a response to a command. + * @ipts: The IPTS driver context. + * @code: The type of the command / response. @@ -986,7 +867,7 @@ index 000000000000..924758ffee67 +int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, + struct ipts_response *rsp, u64 timeout); + -+/* ++/** + * ipts_cmd_recv() - Receives a response to a command. + * @ipts: The IPTS driver context. + * @code: The type of the command / response. @@ -1000,7 +881,7 @@ index 000000000000..924758ffee67 + return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); +} + -+/* ++/** + * ipts_cmd_send() - Executes a command on the device. + * @ipts: The IPTS driver context. + * @code: The type of the command to execute. @@ -1014,13 +895,12 @@ index 000000000000..924758ffee67 +#endif /* IPTS_CMD_H */ diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h new file mode 100644 -index 000000000000..3450a95e66ee +index 000000000..ba33259f1 --- /dev/null +++ b/drivers/hid/ipts/context.h -@@ -0,0 +1,51 @@ +@@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -1061,7 +941,9 @@ index 000000000000..3450a95e66ee + struct ipts_buffer feature_report; + struct ipts_buffer descriptor; + ++ bool hid_active; + struct hid_device *hid; ++ + struct ipts_device_info info; + struct ipts_resources resources; + @@ -1071,13 +953,12 @@ index 000000000000..3450a95e66ee +#endif /* IPTS_CONTEXT_H */ diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c new file mode 100644 -index 000000000000..2f61500b5119 +index 000000000..5360842d2 --- /dev/null +++ b/drivers/hid/ipts/control.c -@@ -0,0 +1,495 @@ +@@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -1165,6 +1046,7 @@ index 000000000000..2f61500b5119 + +static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) +{ ++ int i = 0; + int ret = 0; + struct ipts_mem_window cmd = { 0 }; + struct ipts_response rsp = { 0 }; @@ -1175,7 +1057,7 @@ index 000000000000..2f61500b5119 + if (!res) + return -EFAULT; + -+ for (int i = 0; i < IPTS_BUFFERS; i++) { ++ for (i = 0; i < IPTS_BUFFERS; i++) { + cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); + cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); + cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); @@ -1419,12 +1301,6 @@ index 000000000000..2f61500b5119 + return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); +} + -+static inline int ipts_control_reset_sensor(struct ipts_context *ipts) -+{ -+ return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET, -+ IPTS_FEEDBACK_DATA_TYPE_VENDOR, NULL, 0); -+} -+ +int ipts_control_start(struct ipts_context *ipts) +{ + int ret = 0; @@ -1466,9 +1342,9 @@ index 000000000000..2f61500b5119 + } + + /* -+ * Newer devices can be directly initialized in doorbell mode. ++ * Newer devices can be directly initialized in polling mode. + */ -+ ipts->mode = IPTS_MODE_DOORBELL; ++ ipts->mode = IPTS_MODE_POLL; + } + + ret = ipts_control_set_mode(ipts, ipts->mode); @@ -1495,6 +1371,8 @@ index 000000000000..2f61500b5119 + return ret; + } + ++ ipts_hid_enable(ipts); ++ + ret = ipts_hid_init(ipts, info); + if (ret) { + dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); @@ -1511,6 +1389,7 @@ index 000000000000..2f61500b5119 + if (!ipts) + return -EFAULT; + ++ ipts_hid_disable(ipts); + dev_info(ipts->dev, "Stopping IPTS\n"); + + ret = ipts_receiver_stop(ipts); @@ -1519,12 +1398,6 @@ index 000000000000..2f61500b5119 + return ret; + } + -+ ret = ipts_control_reset_sensor(ipts); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to reset sensor: %d\n", ret); -+ return ret; -+ } -+ + ret = ipts_resources_free(&ipts->resources); + if (ret) { + dev_err(ipts->dev, "Failed to free resources: %d\n", ret); @@ -1560,7 +1433,7 @@ index 000000000000..2f61500b5119 + return ret; + + /* -+ * Give the sensor some time to come back from resetting ++ * Wait a second to give the sensor time to fully shut down. + */ + msleep(1000); + @@ -1572,13 +1445,12 @@ index 000000000000..2f61500b5119 +} diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h new file mode 100644 -index 000000000000..744bb92d682a +index 000000000..26629c514 --- /dev/null +++ b/drivers/hid/ipts/control.h -@@ -0,0 +1,127 @@ +@@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -1593,7 +1465,7 @@ index 000000000000..744bb92d682a +#include "spec-data.h" +#include "spec-device.h" + -+/* ++/** + * ipts_control_request_flush() - Stop the data flow. + * @ipts: The IPTS driver context. + * @@ -1604,7 +1476,7 @@ index 000000000000..744bb92d682a + */ +int ipts_control_request_flush(struct ipts_context *ipts); + -+/* ++/** + * ipts_control_wait_flush() - Wait until data flow has been stopped. + * @ipts: The IPTS driver context. + * @@ -1612,7 +1484,7 @@ index 000000000000..744bb92d682a + */ +int ipts_control_wait_flush(struct ipts_context *ipts); + -+/* ++/** + * ipts_control_wait_flush() - Notify the device that the driver can receive new data. + * @ipts: The IPTS driver context. + * @@ -1620,19 +1492,19 @@ index 000000000000..744bb92d682a + */ +int ipts_control_request_data(struct ipts_context *ipts); + -+/* ++/** + * ipts_control_wait_data() - Wait until new data is available. + * @ipts: The IPTS driver context. + * @block: Whether to block execution until data is available. + * -+ * In doorbell mode, this function will never return while the data flow is active. Instead, -+ * the doorbell will be incremented when new data is available. ++ * In poll mode, this function will never return while the data flow is active. Instead, ++ * the poll will be incremented when new data is available. + * + * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. + */ +int ipts_control_wait_data(struct ipts_context *ipts, bool block); + -+/* ++/** + * ipts_control_send_feedback() - Submits a feedback buffer to the device. + * @ipts: The IPTS driver context. + * @buffer: The ID of the buffer containing feedback data. @@ -1641,7 +1513,7 @@ index 000000000000..744bb92d682a + */ +int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); + -+/* ++/** + * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. + * @ipts: The IPTS driver context. + * @cmd: The command that will be run on the device. @@ -1658,7 +1530,7 @@ index 000000000000..744bb92d682a +int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, + enum ipts_feedback_data_type type, void *data, size_t size); + -+/* ++/** + * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. + * @ipts: The IPTS driver context. + * @buffer: The buffer that has been processed and can be refilled. @@ -1678,7 +1550,7 @@ index 000000000000..744bb92d682a + return ipts_control_send_feedback(ipts, buffer); +} + -+/* ++/** + * ipts_control_start() - Initialized the device and starts the data flow. + * @ipts: The IPTS driver context. + * @@ -1686,7 +1558,7 @@ index 000000000000..744bb92d682a + */ +int ipts_control_start(struct ipts_context *ipts); + -+/* ++/** + * ipts_control_stop() - Stops the data flow and resets the device. + * @ipts: The IPTS driver context. + * @@ -1694,7 +1566,7 @@ index 000000000000..744bb92d682a + */ +int ipts_control_stop(struct ipts_context *ipts); + -+/* ++/** + * ipts_control_restart() - Stops the device and starts it again. + * @ipts: The IPTS driver context. + * @@ -1705,13 +1577,12 @@ index 000000000000..744bb92d682a +#endif /* IPTS_CONTROL_H */ diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h new file mode 100644 -index 000000000000..c058974a03a1 +index 000000000..307438c7c --- /dev/null +++ b/drivers/hid/ipts/desc.h -@@ -0,0 +1,81 @@ +@@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2022-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -1790,133 +1661,231 @@ index 000000000000..c058974a03a1 +}; + +#endif /* IPTS_DESC_H */ -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c +diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c new file mode 100644 -index 000000000000..6782394e8dde +index 000000000..ecbb3a8bd --- /dev/null -+++ b/drivers/hid/ipts/hid.c -@@ -0,0 +1,348 @@ ++++ b/drivers/hid/ipts/eds1.c +@@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation -+ * Copyright (c) 2022-2023 Dorian Stoll ++ * Copyright (c) 2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus + */ + -+#include <linux/completion.h> ++#include <linux/err.h> +#include <linux/gfp.h> +#include <linux/hid.h> -+#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include "context.h" +#include "control.h" +#include "desc.h" -+#include "hid.h" -+#include "spec-data.h" +#include "spec-device.h" -+#include "spec-hid.h" + -+static int ipts_hid_start(struct hid_device *hid) ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) +{ ++ size_t size = 0; ++ u8 *buffer = NULL; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!desc_buffer) ++ return -EFAULT; ++ ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); ++ ++ buffer = kzalloc(size, GFP_KERNEL); ++ if (!buffer) ++ return -ENOMEM; ++ ++ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, ++ sizeof(ipts_fallback_descriptor)); ++ ++ *desc_size = size; ++ *desc_buffer = buffer; ++ + return 0; +} + -+static void ipts_hid_stop(struct hid_device *hid) ++static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) +{ -+} ++ int ret = 0; + -+static int ipts_hid_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ + if (!ipts) + return -EFAULT; + + if (ipts->mode == mode) + return 0; + -+ /* -+ * This is only allowed on older devices. -+ */ -+ if (ipts->info.intf_eds > 1) -+ return 0; -+ + ipts->mode = mode; -+ return ipts_control_restart(ipts); ++ ++ ret = ipts_control_restart(ipts); ++ if (ret) ++ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); ++ ++ return ret; +} + -+static int ipts_hid_parse(struct hid_device *hid) ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) +{ + int ret = 0; -+ struct ipts_context *ipts = NULL; + -+ bool has_native_descriptor = false; ++ if (!ipts) ++ return -EFAULT; + -+ u8 *buffer = NULL; -+ size_t size = 0; ++ if (!buffer) ++ return -EFAULT; + -+ if (!hid) -+ return -ENODEV; ++ if (report_id != IPTS_HID_REPORT_SET_MODE) ++ return -EIO; + -+ ipts = hid->driver_data; ++ if (report_type != HID_FEATURE_REPORT) ++ return -EIO; ++ ++ if (size != 2) ++ return -EINVAL; ++ ++ /* ++ * Implement mode switching report for older devices without native HID support. ++ */ ++ ++ if (request_type == HID_REQ_GET_REPORT) { ++ memset(buffer, 0, size); ++ buffer[0] = report_id; ++ buffer[1] = ipts->mode; ++ } else if (request_type == HID_REQ_SET_REPORT) { ++ return ipts_eds1_switch_mode(ipts, buffer[1]); ++ } else { ++ return -EIO; ++ } ++ ++ return ret; ++} +diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h +new file mode 100644 +index 000000000..eeeb6575e +--- /dev/null ++++ b/drivers/hid/ipts/eds1.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include <linux/hid.h> ++#include <linux/types.h> ++ ++#include "context.h" ++ ++/** ++ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds1_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ 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 000000000..198dc65d7 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.c +@@ -0,0 +1,144 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include <linux/completion.h> ++#include <linux/err.h> ++#include <linux/gfp.h> ++#include <linux/mutex.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++ ++#include "context.h" ++#include "control.h" ++#include "desc.h" ++#include "spec-data.h" ++ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) ++{ ++ size_t size = 0; ++ u8 *buffer = NULL; + + if (!ipts) + return -EFAULT; + -+ size = sizeof(ipts_singletouch_descriptor); -+ has_native_descriptor = ipts->descriptor.address && ipts->descriptor.size > 0; ++ if (!desc_buffer) ++ return -EFAULT; + -+ if (has_native_descriptor) -+ size += ipts->descriptor.size; -+ else -+ size += sizeof(ipts_fallback_descriptor); ++ if (!desc_size) ++ return -EFAULT; ++ ++ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; + + buffer = kzalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); ++ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, ++ ipts->descriptor.size); + -+ if (has_native_descriptor) { -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ } else { -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ } -+ -+ ret = hid_parse_report(hid, buffer, size); -+ kfree(buffer); -+ -+ if (ret) { -+ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); -+ return ret; -+ } ++ *desc_size = size; ++ *desc_buffer = buffer; + + return 0; +} + -+static int ipts_hid_get_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf, -+ size_t size, enum ipts_feedback_data_type type) ++static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) +{ + int ret = 0; + + if (!ipts) + return -EFAULT; + -+ if (!buf) ++ if (!buffer) + return -EFAULT; + + mutex_lock(&ipts->feature_lock); + -+ memset(buf, 0, size); -+ buf[0] = reportnum; ++ memset(buffer, 0, size); ++ buffer[0] = report_id; + + memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); + reinit_completion(&ipts->feature_event); + -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size); ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); + if (ret) { + dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); + goto out; @@ -1940,40 +1909,154 @@ index 000000000000..6782394e8dde + } + + ret = ipts->feature_report.size; -+ memcpy(buf, ipts->feature_report.address, ipts->feature_report.size); ++ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); + +out: + mutex_unlock(&ipts->feature_lock); + return ret; +} + -+static int ipts_hid_set_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf, -+ size_t size, enum ipts_feedback_data_type type) ++static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum ipts_feedback_data_type type) +{ + int ret = 0; + + if (!ipts) + return -EFAULT; + -+ if (!buf) ++ if (!buffer) + return -EFAULT; + -+ buf[0] = reportnum; ++ buffer[0] = report_id; + -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size); ++ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); + if (ret) + dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); + + return ret; +} + -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char reportnum, __u8 *buf, -+ size_t size, unsigned char rtype, int reqtype) ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ enum hid_report_type report_type, enum hid_class_request request_type) ++{ ++ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!buffer) ++ return -EFAULT; ++ ++ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; ++ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) ++ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ else ++ return -EIO; ++ ++ if (request_type == HID_REQ_GET_REPORT) ++ return ipts_eds2_get_feature(ipts, buffer, size, report_id, feedback_type); ++ else ++ return ipts_eds2_set_feature(ipts, buffer, size, report_id, feedback_type); ++} +diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h +new file mode 100644 +index 000000000..064e37169 +--- /dev/null ++++ b/drivers/hid/ipts/eds2.h +@@ -0,0 +1,35 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include <linux/hid.h> ++#include <linux/types.h> ++ ++#include "context.h" ++ ++/** ++ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. ++ * @ipts: The IPTS driver context. ++ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. ++ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); ++ ++/** ++ * ipts_eds2_raw_request() - Executes an output or feature report on the device. ++ * @ipts: The IPTS driver context. ++ * @buffer: The buffer containing the report. ++ * @size: The size of the buffer. ++ * @report_id: The HID report ID. ++ * @report_type: Whether this report is an output or a feature report. ++ * @request_type: Whether this report requests or sends data. ++ * ++ * Returns: 0 on success, <0 on error. ++ */ ++int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, ++ 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 000000000..e34a1a4f9 +--- /dev/null ++++ b/drivers/hid/ipts/hid.c +@@ -0,0 +1,225 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2022-2023 Dorian Stoll ++ * ++ * Linux driver for Intel Precise Touch & Stylus ++ */ ++ ++#include <linux/completion.h> ++#include <linux/err.h> ++#include <linux/gfp.h> ++#include <linux/hid.h> ++#include <linux/mutex.h> ++#include <linux/slab.h> ++#include <linux/types.h> ++ ++#include "context.h" ++#include "desc.h" ++#include "eds1.h" ++#include "eds2.h" ++#include "hid.h" ++#include "spec-data.h" ++#include "spec-hid.h" ++ ++void ipts_hid_enable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, true); ++} ++ ++void ipts_hid_disable(struct ipts_context *ipts) ++{ ++ WRITE_ONCE(ipts->hid_active, false); ++} ++ ++static int ipts_hid_start(struct hid_device *hid) ++{ ++ return 0; ++} ++ ++static void ipts_hid_stop(struct hid_device *hid) ++{ ++} ++ ++static int ipts_hid_parse(struct hid_device *hid) +{ + int ret = 0; + struct ipts_context *ipts = NULL; + -+ enum ipts_feedback_data_type type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; ++ u8 *buffer = NULL; ++ size_t size = 0; + + if (!hid) + return -ENODEV; @@ -1983,34 +2066,32 @@ index 000000000000..6782394e8dde + if (!ipts) + return -EFAULT; + -+ if (!buf) -+ return -EFAULT; ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; + -+ if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) -+ type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) -+ type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) -+ type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; ++ if (ipts->info.intf_eds == 1) ++ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); + else -+ return -EIO; ++ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); + -+ // Implemente mode switching report for older devices without native HID support -+ if (type == IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES && reportnum == IPTS_HID_REPORT_SET_MODE) { -+ ret = ipts_hid_switch_mode(ipts, buf[1]); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ return ret; -+ } ++ if (ret) { ++ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); ++ return ret; + } + -+ if (reqtype == HID_REQ_GET_REPORT) -+ return ipts_hid_get_feature(ipts, reportnum, buf, size, type); -+ else -+ return ipts_hid_set_feature(ipts, reportnum, buf, size, type); ++ ret = hid_parse_report(hid, buffer, size); ++ kfree(buffer); ++ ++ if (ret) { ++ dev_err(ipts->dev, "Failed to parse HID descriptor: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; +} + -+static int ipts_hid_output_report(struct hid_device *hid, __u8 *data, size_t size) ++static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, ++ size_t size, unsigned char report_type, int request_type) +{ + struct ipts_context *ipts = NULL; + @@ -2019,8 +2100,19 @@ index 000000000000..6782394e8dde + + ipts = hid->driver_data; + -+ return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, -+ IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, data, size); ++ if (!ipts) ++ return -EFAULT; ++ ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ ++ if (ipts->info.intf_eds == 1) { ++ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } else { ++ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, ++ request_type); ++ } +} + +static struct hid_ll_driver ipts_hid_driver = { @@ -2030,12 +2122,10 @@ index 000000000000..6782394e8dde + .close = ipts_hid_stop, + .parse = ipts_hid_parse, + .raw_request = ipts_hid_raw_request, -+ .output_report = ipts_hid_output_report, +}; + +int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) +{ -+ int ret = 0; + u8 *temp = NULL; + struct ipts_hid_header *frame = NULL; + struct ipts_data_header *header = NULL; @@ -2046,8 +2136,14 @@ index 000000000000..6782394e8dde + if (!ipts->hid) + return -ENODEV; + ++ if (!READ_ONCE(ipts->hid_active)) ++ return -ENODEV; ++ + header = (struct ipts_data_header *)ipts->resources.data[buffer].address; + ++ temp = ipts->resources.report.address; ++ memset(temp, 0, ipts->resources.report.size); ++ + if (!header) + return -EFAULT; + @@ -2071,10 +2167,6 @@ index 000000000000..6782394e8dde + if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) + return -ERANGE; + -+ temp = kzalloc(IPTS_HID_REPORT_DATA_SIZE, GFP_KERNEL); -+ if (!temp) -+ return -ENOMEM; -+ + /* + * Synthesize a HID report matching the devices that natively send HID reports + */ @@ -2086,10 +2178,7 @@ index 000000000000..6782394e8dde + + memcpy(frame->data, header->data, header->size); + -+ ret = hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -+ kfree(temp); -+ -+ return ret; ++ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); +} + +int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) @@ -2116,7 +2205,7 @@ index 000000000000..6782394e8dde + + ipts->hid->vendor = info.vendor; + ipts->hid->product = info.product; -+ ipts->hid->group = HID_GROUP_MULTITOUCH; ++ ipts->hid->group = HID_GROUP_GENERIC; + + snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, + info.product); @@ -2146,13 +2235,12 @@ index 000000000000..6782394e8dde +} diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h new file mode 100644 -index 000000000000..62bf3cd48608 +index 000000000..1ebe77447 --- /dev/null +++ b/drivers/hid/ipts/hid.h -@@ -0,0 +1,22 @@ +@@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2022-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2166,6 +2254,9 @@ index 000000000000..62bf3cd48608 +#include "context.h" +#include "spec-device.h" + ++void ipts_hid_enable(struct ipts_context *ipts); ++void ipts_hid_disable(struct ipts_context *ipts); ++ +int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); + +int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); @@ -2174,13 +2265,12 @@ index 000000000000..62bf3cd48608 +#endif /* IPTS_HID_H */ diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c new file mode 100644 -index 000000000000..0f20c6c08c38 +index 000000000..fb5b5c13e --- /dev/null +++ b/drivers/hid/ipts/main.c -@@ -0,0 +1,127 @@ +@@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2307,13 +2397,12 @@ index 000000000000..0f20c6c08c38 +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c new file mode 100644 -index 000000000000..26666fd99b0c +index 000000000..1e0395cea --- /dev/null +++ b/drivers/hid/ipts/mei.c -@@ -0,0 +1,189 @@ +@@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2502,13 +2591,12 @@ index 000000000000..26666fd99b0c +} diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h new file mode 100644 -index 000000000000..eadacae54c40 +index 000000000..973bade6b --- /dev/null +++ b/drivers/hid/ipts/mei.h -@@ -0,0 +1,67 @@ +@@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2539,7 +2627,7 @@ index 000000000000..eadacae54c40 + struct rw_semaphore message_lock; +}; + -+/* ++/** + * ipts_mei_recv() - Receive data from a MEI device. + * @mei: The IPTS MEI device context. + * @code: The IPTS command code to look for. @@ -2553,7 +2641,7 @@ index 000000000000..eadacae54c40 +int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, + u64 timeout); + -+/* ++/** + * ipts_mei_send() - Send data to a MEI device. + * @ipts: The IPTS MEI device context. + * @data: The data to send. @@ -2563,7 +2651,7 @@ index 000000000000..eadacae54c40 + */ +int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); + -+/* ++/** + * ipts_mei_init() - Initialize the MEI device context. + * @mei: The MEI device context to initialize. + * @cldev: The MEI device the context will be bound to. @@ -2575,13 +2663,12 @@ index 000000000000..eadacae54c40 +#endif /* IPTS_MEI_H */ diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c new file mode 100644 -index 000000000000..77234f9e0e17 +index 000000000..ef66c3c9d --- /dev/null +++ b/drivers/hid/ipts/receiver.c -@@ -0,0 +1,249 @@ +@@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2623,7 +2710,7 @@ index 000000000000..77234f9e0e17 + * n seconds, sleep longer to avoid wasting CPU cycles. + */ + if (last + n > ktime_get_seconds()) -+ msleep(20); ++ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); + else + msleep(200); +} @@ -2647,7 +2734,9 @@ index 000000000000..77234f9e0e17 + dev_info(ipts->dev, "IPTS running in event mode\n"); + + while (!ipts_thread_should_stop(thread)) { -+ for (int i = 0; i < IPTS_BUFFERS; i++) { ++ int i = 0; ++ ++ for (i = 0; i < IPTS_BUFFERS; i++) { + ret = ipts_control_wait_data(ipts, false); + if (ret == -EAGAIN) + break; @@ -2707,7 +2796,7 @@ index 000000000000..77234f9e0e17 + return 0; +} + -+static int ipts_receiver_doorbell_loop(struct ipts_thread *thread) ++static int ipts_receiver_poll_loop(struct ipts_thread *thread) +{ + int ret = 0; + u32 buffer = 0; @@ -2726,7 +2815,7 @@ index 000000000000..77234f9e0e17 + if (!ipts) + return -EFAULT; + -+ dev_info(ipts->dev, "IPTS running in doorbell mode\n"); ++ dev_info(ipts->dev, "IPTS running in poll mode\n"); + + while (true) { + if (ipts_thread_should_stop(thread)) { @@ -2798,9 +2887,9 @@ index 000000000000..77234f9e0e17 + if (ipts->mode == IPTS_MODE_EVENT) { + ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, + "ipts_event"); -+ } else if (ipts->mode == IPTS_MODE_DOORBELL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_doorbell_loop, ipts, -+ "ipts_doorbell"); ++ } else if (ipts->mode == IPTS_MODE_POLL) { ++ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, ++ "ipts_poll"); + } else { + ret = -EINVAL; + } @@ -2830,13 +2919,12 @@ index 000000000000..77234f9e0e17 +} diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h new file mode 100644 -index 000000000000..96070f34fbca +index 000000000..3de7da62d --- /dev/null +++ b/drivers/hid/ipts/receiver.h -@@ -0,0 +1,17 @@ +@@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -2853,21 +2941,22 @@ index 000000000000..96070f34fbca +#endif /* IPTS_RECEIVER_H */ diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c new file mode 100644 -index 000000000000..80ba5885bb55 +index 000000000..cc14653b2 --- /dev/null +++ b/drivers/hid/ipts/resources.c -@@ -0,0 +1,108 @@ +@@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus + */ + +#include <linux/dma-mapping.h> ++#include <linux/slab.h> +#include <linux/types.h> + ++#include "desc.h" +#include "resources.h" +#include "spec-device.h" + @@ -2908,16 +2997,22 @@ index 000000000000..80ba5885bb55 +{ + int ret = 0; + ++ /* ++ * Some compilers (AOSP clang) complain about a redefined ++ * variable when this is declared inside of the for loop. ++ */ ++ int i = 0; ++ + if (!res) + return -EFAULT; + -+ for (int i = 0; i < IPTS_BUFFERS; i++) { ++ for (i = 0; i < IPTS_BUFFERS; i++) { + ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); + if (ret) + goto err; + } + -+ for (int i = 0; i < IPTS_BUFFERS; i++) { ++ for (i = 0; i < IPTS_BUFFERS; i++) { + ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); + if (ret) + goto err; @@ -2939,6 +3034,16 @@ index 000000000000..80ba5885bb55 + if (ret) + goto err; + ++ if (!res->report.address) { ++ res->report.size = IPTS_HID_REPORT_DATA_SIZE; ++ res->report.address = kzalloc(res->report.size, GFP_KERNEL); ++ ++ if (!res->report.address) { ++ ret = -ENOMEM; ++ goto err; ++ } ++ } ++ + return 0; + +err: @@ -2949,13 +3054,15 @@ index 000000000000..80ba5885bb55 + +int ipts_resources_free(struct ipts_resources *res) +{ ++ int i = 0; ++ + if (!res) + return -EFAULT; + -+ for (int i = 0; i < IPTS_BUFFERS; i++) ++ for (i = 0; i < IPTS_BUFFERS; i++) + ipts_resources_free_buffer(&res->data[i]); + -+ for (int i = 0; i < IPTS_BUFFERS; i++) ++ for (i = 0; i < IPTS_BUFFERS; i++) + ipts_resources_free_buffer(&res->feedback[i]); + + ipts_resources_free_buffer(&res->doorbell); @@ -2963,17 +3070,20 @@ index 000000000000..80ba5885bb55 + ipts_resources_free_buffer(&res->hid2me); + ipts_resources_free_buffer(&res->descriptor); + ++ kfree(res->report.address); ++ res->report.address = NULL; ++ res->report.size = 0; ++ + return 0; +} diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h new file mode 100644 -index 000000000000..6cbb24a8a054 +index 000000000..2068e1328 --- /dev/null +++ b/drivers/hid/ipts/resources.h -@@ -0,0 +1,39 @@ +@@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -3004,6 +3114,9 @@ index 000000000000..6cbb24a8a054 + struct ipts_buffer hid2me; + + struct ipts_buffer descriptor; ++ ++ // Buffer for synthesizing HID reports ++ struct ipts_buffer report; +}; + +int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); @@ -3012,7 +3125,7 @@ index 000000000000..6cbb24a8a054 +#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 000000000..e8dd98895 --- /dev/null +++ b/drivers/hid/ipts/spec-data.h @@ -0,0 +1,100 @@ @@ -3118,10 +3231,10 @@ 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..93f673d981f7 +index 000000000..41845f9d9 --- /dev/null +++ b/drivers/hid/ipts/spec-device.h -@@ -0,0 +1,285 @@ +@@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2016 Intel Corporation @@ -3233,14 +3346,14 @@ index 000000000000..93f673d981f7 + +/** + * enum ipts_mode - Configures what data the device produces and how its sent. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_DOORBELL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. ++ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. ++ * Older devices will return singletouch data in this mode. ++ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. ++ * Older devices will return multitouch data in this mode. + */ +enum ipts_mode { + IPTS_MODE_EVENT = 0x00, -+ IPTS_MODE_DOORBELL = 0x01, ++ IPTS_MODE_POLL = 0x01, +}; + +/** @@ -3377,14 +3490,19 @@ index 000000000000..93f673d981f7 + +/** + * struct ipts_device_info - Vendor information of the IPTS device. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @vendor: Vendor ID of this device. ++ * @product: Product ID of this device. ++ * @hw_version: Hardware revision of this device. ++ * @fw_version: Firmware revision of this device. ++ * @data_size: Requested size for a data buffer. ++ * @feedback_size: Requested size for a feedback buffer. ++ * @mode: Mode that the device currently operates in. ++ * @max_contacts: Maximum amount of concurrent touches the sensor can process. ++ * @sensor_min_eds: The minimum EDS version supported by the sensor. ++ * @sensor_max_eds: The maximum EDS version supported by the sensor. ++ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. ++ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. ++ * @intf_eds: The EDS version implemented by the interface between ME and host. + */ +struct ipts_device_info { + u16 vendor; @@ -3409,13 +3527,12 @@ index 000000000000..93f673d981f7 +#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..ea70f29ff00c +index 000000000..5a58d4a0a --- /dev/null +++ b/drivers/hid/ipts/spec-hid.h -@@ -0,0 +1,35 @@ +@@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020-2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -3450,13 +3567,12 @@ index 000000000000..ea70f29ff00c +#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..8b46f775c107 +index 000000000..355e92bea --- /dev/null +++ b/drivers/hid/ipts/thread.c -@@ -0,0 +1,85 @@ +@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -3541,13 +3657,12 @@ index 000000000000..8b46f775c107 +} diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h new file mode 100644 -index 000000000000..a314843599fc +index 000000000..1f966b8b3 --- /dev/null +++ b/drivers/hid/ipts/thread.h -@@ -0,0 +1,60 @@ +@@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* -+ * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2023 Dorian Stoll + * + * Linux driver for Intel Precise Touch & Stylus @@ -3576,7 +3691,7 @@ index 000000000000..a314843599fc + int (*threadfn)(struct ipts_thread *thread); +}; + -+/* ++/** + * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. + * @thread: The current thread. + * @@ -3584,7 +3699,7 @@ index 000000000000..a314843599fc + */ +bool ipts_thread_should_stop(struct ipts_thread *thread); + -+/* ++/** + * ipts_thread_start() - Starts an IPTS thread. + * @thread: The thread to initialize and start. + * @threadfn: The function to execute. @@ -3596,7 +3711,7 @@ index 000000000000..a314843599fc +int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), + void *data, const char name[]); + -+/* ++/** + * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. + * @thread: The thread that should stop. + * @@ -3605,1586 +3720,9 @@ index 000000000000..a314843599fc +int ipts_thread_stop(struct ipts_thread *thread); + +#endif /* IPTS_THREAD_H */ --- -2.41.0 - -From 741a055a0f89c4f6db9d908a86c3ad0699928fca Mon Sep 17 00:00:00 2001 -From: Dorian Stoll <dorian.stoll@tmsp.io> -Date: Fri, 28 Apr 2023 15:41:12 +0200 -Subject: [PATCH] Update IPTS from module repo - -Changes: - * Fix redefinition error on AOSP clang - * Increase the polling frequency to reduce latency - * Don't allocate a new buffer for every HID report - * Always use the generic HID driver instead of forcing hid-multitouch - -Based on https://github.com/linux-surface/intel-precise-touch/commit/a2b675d72dbde80ebe36a5b6ceaebd596c030314 - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ipts ---- - drivers/hid/ipts/hid.c | 15 +++++---------- - drivers/hid/ipts/receiver.c | 2 +- - drivers/hid/ipts/resources.c | 35 +++++++++++++++++++++++++++++++---- - drivers/hid/ipts/resources.h | 3 +++ - 4 files changed, 40 insertions(+), 15 deletions(-) - -diff --git a/drivers/hid/ipts/hid.c b/drivers/hid/ipts/hid.c -index 6782394e8dde..a2471219615b 100644 ---- a/drivers/hid/ipts/hid.c -+++ b/drivers/hid/ipts/hid.c -@@ -237,7 +237,6 @@ static struct hid_ll_driver ipts_hid_driver = { - - int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) - { -- int ret = 0; - u8 *temp = NULL; - struct ipts_hid_header *frame = NULL; - struct ipts_data_header *header = NULL; -@@ -250,6 +249,9 @@ int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) - - header = (struct ipts_data_header *)ipts->resources.data[buffer].address; - -+ temp = ipts->resources.report.address; -+ memset(temp, 0, ipts->resources.report.size); -+ - if (!header) - return -EFAULT; - -@@ -273,10 +275,6 @@ int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) - if (header->size + 3 + sizeof(struct ipts_hid_header) > IPTS_HID_REPORT_DATA_SIZE) - return -ERANGE; - -- temp = kzalloc(IPTS_HID_REPORT_DATA_SIZE, GFP_KERNEL); -- if (!temp) -- return -ENOMEM; -- - /* - * Synthesize a HID report matching the devices that natively send HID reports - */ -@@ -288,10 +286,7 @@ int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) - - memcpy(frame->data, header->data, header->size); - -- ret = hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); -- kfree(temp); -- -- return ret; -+ return hid_input_report(ipts->hid, HID_INPUT_REPORT, temp, IPTS_HID_REPORT_DATA_SIZE, 1); - } - - int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) -@@ -318,7 +313,7 @@ int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info) - - ipts->hid->vendor = info.vendor; - ipts->hid->product = info.product; -- ipts->hid->group = HID_GROUP_MULTITOUCH; -+ ipts->hid->group = HID_GROUP_GENERIC; - - snprintf(ipts->hid->name, sizeof(ipts->hid->name), "IPTS %04X:%04X", info.vendor, - info.product); -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -index 77234f9e0e17..f56e9ed32d57 100644 ---- a/drivers/hid/ipts/receiver.c -+++ b/drivers/hid/ipts/receiver.c -@@ -42,7 +42,7 @@ static void ipts_receiver_backoff(time64_t last, u32 n) - * n seconds, sleep longer to avoid wasting CPU cycles. - */ - if (last + n > ktime_get_seconds()) -- msleep(20); -+ usleep_range(1 * USEC_PER_MSEC, 5 * USEC_PER_MSEC); - else - msleep(200); - } -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -index 80ba5885bb55..5e924d58c488 100644 ---- a/drivers/hid/ipts/resources.c -+++ b/drivers/hid/ipts/resources.c -@@ -9,6 +9,7 @@ - #include <linux/dma-mapping.h> - #include <linux/types.h> - -+#include "desc.h" - #include "resources.h" - #include "spec-device.h" - -@@ -49,16 +50,22 @@ int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t d - { - int ret = 0; - -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ - if (!res) - return -EFAULT; - -- for (int i = 0; i < IPTS_BUFFERS; i++) { -+ for (i = 0; i < IPTS_BUFFERS; i++) { - ret = ipts_resources_alloc_buffer(&res->data[i], dev, ds); - if (ret) - goto err; - } - -- for (int i = 0; i < IPTS_BUFFERS; i++) { -+ for (i = 0; i < IPTS_BUFFERS; i++) { - ret = ipts_resources_alloc_buffer(&res->feedback[i], dev, fs); - if (ret) - goto err; -@@ -80,6 +87,16 @@ int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t d - if (ret) - goto err; - -+ if (!res->report.address) { -+ res->report.size = IPTS_HID_REPORT_DATA_SIZE; -+ res->report.address = kzalloc(res->report.size, GFP_KERNEL); -+ -+ if (!res->report.address) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ } -+ - return 0; - - err: -@@ -90,13 +107,19 @@ int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t d - - int ipts_resources_free(struct ipts_resources *res) - { -+ /* -+ * Some compilers (AOSP clang) complain about a redefined -+ * variable when this is declared inside of the for loop. -+ */ -+ int i = 0; -+ - if (!res) - return -EFAULT; - -- for (int i = 0; i < IPTS_BUFFERS; i++) -+ for (i = 0; i < IPTS_BUFFERS; i++) - ipts_resources_free_buffer(&res->data[i]); - -- for (int i = 0; i < IPTS_BUFFERS; i++) -+ for (i = 0; i < IPTS_BUFFERS; i++) - ipts_resources_free_buffer(&res->feedback[i]); - - ipts_resources_free_buffer(&res->doorbell); -@@ -104,5 +127,9 @@ int ipts_resources_free(struct ipts_resources *res) - ipts_resources_free_buffer(&res->hid2me); - ipts_resources_free_buffer(&res->descriptor); - -+ kfree(res->report.address); -+ res->report.address = NULL; -+ res->report.size = 0; -+ - return 0; - } -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -index 6cbb24a8a054..e0c400f420b9 100644 ---- a/drivers/hid/ipts/resources.h -+++ b/drivers/hid/ipts/resources.h -@@ -31,6 +31,9 @@ struct ipts_resources { - struct ipts_buffer hid2me; - - struct ipts_buffer descriptor; -+ -+ // Buffer for synthesizing HID reports -+ struct ipts_buffer report; - }; - - int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t ds, size_t fs); --- -2.41.0 - -From 3416fa5a1a0bd6153d50e309ac1bf59bd55d95b6 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll <dorian.stoll@tmsp.io> -Date: Mon, 17 Jul 2023 18:10:43 +0200 -Subject: [PATCH] Update IPTS from module repo - -Changes: -* Remove usages of C11 for compatibility with older (Android) kernels -* Remove sensor reset during shutdown -* Fix compiling resources.c on Android-x86 kernel -* Split out HID behaviour for different EDS versions into different files -* Fix kernel-doc comments -* Add missing docs for members of the device info struct -* Drop Intel copyright -* Rename doorbell mode to poll mode -* Disable the HID interface when the hardware is shutting down. - -Based on https://github.com/linux-surface/intel-precise-touch/commit/56765da3f87d87c5e5cf09e928abe0f579525e5e - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ipts ---- - drivers/hid/ipts/Makefile | 2 + - drivers/hid/ipts/cmd.c | 1 - - drivers/hid/ipts/cmd.h | 7 +- - drivers/hid/ipts/context.h | 3 +- - drivers/hid/ipts/control.c | 25 ++--- - drivers/hid/ipts/control.h | 25 +++-- - drivers/hid/ipts/desc.h | 1 - - drivers/hid/ipts/eds1.c | 103 ++++++++++++++++++ - drivers/hid/ipts/eds1.h | 35 +++++++ - drivers/hid/ipts/eds2.c | 144 ++++++++++++++++++++++++++ - drivers/hid/ipts/eds2.h | 35 +++++++ - drivers/hid/ipts/hid.c | 184 ++++++--------------------------- - drivers/hid/ipts/hid.h | 4 +- - drivers/hid/ipts/main.c | 1 - - drivers/hid/ipts/mei.c | 1 - - drivers/hid/ipts/mei.h | 7 +- - drivers/hid/ipts/receiver.c | 15 +-- - drivers/hid/ipts/receiver.h | 1 - - drivers/hid/ipts/resources.c | 6 +- - drivers/hid/ipts/resources.h | 1 - - drivers/hid/ipts/spec-device.h | 31 +++--- - drivers/hid/ipts/spec-hid.h | 1 - - drivers/hid/ipts/thread.c | 1 - - drivers/hid/ipts/thread.h | 7 +- - 24 files changed, 413 insertions(+), 228 deletions(-) - create mode 100644 drivers/hid/ipts/eds1.c - create mode 100644 drivers/hid/ipts/eds1.h - create mode 100644 drivers/hid/ipts/eds2.c - create mode 100644 drivers/hid/ipts/eds2.h - -diff --git a/drivers/hid/ipts/Makefile b/drivers/hid/ipts/Makefile -index 0fe655bccdc0..883896f68e6a 100644 ---- a/drivers/hid/ipts/Makefile -+++ b/drivers/hid/ipts/Makefile -@@ -6,6 +6,8 @@ - obj-$(CONFIG_HID_IPTS) += ipts.o - ipts-objs := cmd.o - ipts-objs += control.o -+ipts-objs += eds1.o -+ipts-objs += eds2.o - ipts-objs += hid.o - ipts-objs += main.o - ipts-objs += mei.o -diff --git a/drivers/hid/ipts/cmd.c b/drivers/hid/ipts/cmd.c -index 7fd69271ccd5..63a4934bbc5f 100644 ---- a/drivers/hid/ipts/cmd.c -+++ b/drivers/hid/ipts/cmd.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/cmd.h b/drivers/hid/ipts/cmd.h -index 924758ffee67..2b4079075b64 100644 ---- a/drivers/hid/ipts/cmd.h -+++ b/drivers/hid/ipts/cmd.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -19,7 +18,7 @@ - */ - #define IPTS_CMD_DEFAULT_TIMEOUT 1000 - --/* -+/** - * ipts_cmd_recv_timeout() - Receives a response to a command. - * @ipts: The IPTS driver context. - * @code: The type of the command / response. -@@ -33,7 +32,7 @@ - int ipts_cmd_recv_timeout(struct ipts_context *ipts, enum ipts_command_code code, - struct ipts_response *rsp, u64 timeout); - --/* -+/** - * ipts_cmd_recv() - Receives a response to a command. - * @ipts: The IPTS driver context. - * @code: The type of the command / response. -@@ -47,7 +46,7 @@ static inline int ipts_cmd_recv(struct ipts_context *ipts, enum ipts_command_cod - return ipts_cmd_recv_timeout(ipts, code, rsp, IPTS_CMD_DEFAULT_TIMEOUT); - } - --/* -+/** - * ipts_cmd_send() - Executes a command on the device. - * @ipts: The IPTS driver context. - * @code: The type of the command to execute. -diff --git a/drivers/hid/ipts/context.h b/drivers/hid/ipts/context.h -index 3450a95e66ee..ba33259f1f7c 100644 ---- a/drivers/hid/ipts/context.h -+++ b/drivers/hid/ipts/context.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -41,7 +40,9 @@ struct ipts_context { - struct ipts_buffer feature_report; - struct ipts_buffer descriptor; - -+ bool hid_active; - struct hid_device *hid; -+ - struct ipts_device_info info; - struct ipts_resources resources; - -diff --git a/drivers/hid/ipts/control.c b/drivers/hid/ipts/control.c -index 2f61500b5119..5360842d260b 100644 ---- a/drivers/hid/ipts/control.c -+++ b/drivers/hid/ipts/control.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -88,6 +87,7 @@ static int ipts_control_set_mode(struct ipts_context *ipts, enum ipts_mode mode) - - static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_resources *res) - { -+ int i = 0; - int ret = 0; - struct ipts_mem_window cmd = { 0 }; - struct ipts_response rsp = { 0 }; -@@ -98,7 +98,7 @@ static int ipts_control_set_mem_window(struct ipts_context *ipts, struct ipts_re - if (!res) - return -EFAULT; - -- for (int i = 0; i < IPTS_BUFFERS; i++) { -+ for (i = 0; i < IPTS_BUFFERS; i++) { - cmd.data_addr_lower[i] = lower_32_bits(res->data[i].dma_address); - cmd.data_addr_upper[i] = upper_32_bits(res->data[i].dma_address); - cmd.feedback_addr_lower[i] = lower_32_bits(res->feedback[i].dma_address); -@@ -342,12 +342,6 @@ int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_c - return ipts_control_send_feedback(ipts, IPTS_HID2ME_BUFFER); - } - --static inline int ipts_control_reset_sensor(struct ipts_context *ipts) --{ -- return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_SOFT_RESET, -- IPTS_FEEDBACK_DATA_TYPE_VENDOR, NULL, 0); --} -- - int ipts_control_start(struct ipts_context *ipts) - { - int ret = 0; -@@ -389,9 +383,9 @@ int ipts_control_start(struct ipts_context *ipts) - } - - /* -- * Newer devices can be directly initialized in doorbell mode. -+ * Newer devices can be directly initialized in polling mode. - */ -- ipts->mode = IPTS_MODE_DOORBELL; -+ ipts->mode = IPTS_MODE_POLL; - } - - ret = ipts_control_set_mode(ipts, ipts->mode); -@@ -418,6 +412,8 @@ int ipts_control_start(struct ipts_context *ipts) - return ret; - } - -+ ipts_hid_enable(ipts); -+ - ret = ipts_hid_init(ipts, info); - if (ret) { - dev_err(ipts->dev, "Failed to initialize HID device: %d\n", ret); -@@ -434,6 +430,7 @@ static int _ipts_control_stop(struct ipts_context *ipts) - if (!ipts) - return -EFAULT; - -+ ipts_hid_disable(ipts); - dev_info(ipts->dev, "Stopping IPTS\n"); - - ret = ipts_receiver_stop(ipts); -@@ -442,12 +439,6 @@ static int _ipts_control_stop(struct ipts_context *ipts) - return ret; - } - -- ret = ipts_control_reset_sensor(ipts); -- if (ret) { -- dev_err(ipts->dev, "Failed to reset sensor: %d\n", ret); -- return ret; -- } -- - ret = ipts_resources_free(&ipts->resources); - if (ret) { - dev_err(ipts->dev, "Failed to free resources: %d\n", ret); -@@ -483,7 +474,7 @@ int ipts_control_restart(struct ipts_context *ipts) - return ret; - - /* -- * Give the sensor some time to come back from resetting -+ * Wait a second to give the sensor time to fully shut down. - */ - msleep(1000); - -diff --git a/drivers/hid/ipts/control.h b/drivers/hid/ipts/control.h -index 744bb92d682a..26629c5144ed 100644 ---- a/drivers/hid/ipts/control.h -+++ b/drivers/hid/ipts/control.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -15,7 +14,7 @@ - #include "spec-data.h" - #include "spec-device.h" - --/* -+/** - * ipts_control_request_flush() - Stop the data flow. - * @ipts: The IPTS driver context. - * -@@ -26,7 +25,7 @@ - */ - int ipts_control_request_flush(struct ipts_context *ipts); - --/* -+/** - * ipts_control_wait_flush() - Wait until data flow has been stopped. - * @ipts: The IPTS driver context. - * -@@ -34,7 +33,7 @@ int ipts_control_request_flush(struct ipts_context *ipts); - */ - int ipts_control_wait_flush(struct ipts_context *ipts); - --/* -+/** - * ipts_control_wait_flush() - Notify the device that the driver can receive new data. - * @ipts: The IPTS driver context. - * -@@ -42,19 +41,19 @@ int ipts_control_wait_flush(struct ipts_context *ipts); - */ - int ipts_control_request_data(struct ipts_context *ipts); - --/* -+/** - * ipts_control_wait_data() - Wait until new data is available. - * @ipts: The IPTS driver context. - * @block: Whether to block execution until data is available. - * -- * In doorbell mode, this function will never return while the data flow is active. Instead, -- * the doorbell will be incremented when new data is available. -+ * In poll mode, this function will never return while the data flow is active. Instead, -+ * the poll will be incremented when new data is available. - * - * Returns: 0 on success, <0 on error, -EAGAIN if no data is available. - */ - int ipts_control_wait_data(struct ipts_context *ipts, bool block); - --/* -+/** - * ipts_control_send_feedback() - Submits a feedback buffer to the device. - * @ipts: The IPTS driver context. - * @buffer: The ID of the buffer containing feedback data. -@@ -63,7 +62,7 @@ int ipts_control_wait_data(struct ipts_context *ipts, bool block); - */ - int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); - --/* -+/** - * ipts_control_hid2me_feedback() - Sends HID2ME feedback, a special type of feedback. - * @ipts: The IPTS driver context. - * @cmd: The command that will be run on the device. -@@ -80,7 +79,7 @@ int ipts_control_send_feedback(struct ipts_context *ipts, u32 buffer); - int ipts_control_hid2me_feedback(struct ipts_context *ipts, enum ipts_feedback_cmd_type cmd, - enum ipts_feedback_data_type type, void *data, size_t size); - --/* -+/** - * ipts_control_refill_buffer() - Acknowledges that data in a buffer has been processed. - * @ipts: The IPTS driver context. - * @buffer: The buffer that has been processed and can be refilled. -@@ -100,7 +99,7 @@ static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buff - return ipts_control_send_feedback(ipts, buffer); - } - --/* -+/** - * ipts_control_start() - Initialized the device and starts the data flow. - * @ipts: The IPTS driver context. - * -@@ -108,7 +107,7 @@ static inline int ipts_control_refill_buffer(struct ipts_context *ipts, u32 buff - */ - int ipts_control_start(struct ipts_context *ipts); - --/* -+/** - * ipts_control_stop() - Stops the data flow and resets the device. - * @ipts: The IPTS driver context. - * -@@ -116,7 +115,7 @@ int ipts_control_start(struct ipts_context *ipts); - */ - int ipts_control_stop(struct ipts_context *ipts); - --/* -+/** - * ipts_control_restart() - Stops the device and starts it again. - * @ipts: The IPTS driver context. - * -diff --git a/drivers/hid/ipts/desc.h b/drivers/hid/ipts/desc.h -index c058974a03a1..307438c7c80c 100644 ---- a/drivers/hid/ipts/desc.h -+++ b/drivers/hid/ipts/desc.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2022-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/eds1.c b/drivers/hid/ipts/eds1.c -new file mode 100644 -index 000000000000..ecbb3a8bdaf6 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.c -@@ -0,0 +1,103 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include <linux/err.h> -+#include <linux/gfp.h> -+#include <linux/hid.h> -+#include <linux/slab.h> -+#include <linux/types.h> -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "spec-device.h" -+ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + sizeof(ipts_fallback_descriptor); -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -+ sizeof(ipts_fallback_descriptor)); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds1_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (ipts->mode == mode) -+ return 0; -+ -+ ipts->mode = mode; -+ -+ ret = ipts_control_restart(ipts); -+ if (ret) -+ dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_id != IPTS_HID_REPORT_SET_MODE) -+ return -EIO; -+ -+ if (report_type != HID_FEATURE_REPORT) -+ return -EIO; -+ -+ if (size != 2) -+ return -EINVAL; -+ -+ /* -+ * Implement mode switching report for older devices without native HID support. -+ */ -+ -+ if (request_type == HID_REQ_GET_REPORT) { -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ buffer[1] = ipts->mode; -+ } else if (request_type == HID_REQ_SET_REPORT) { -+ return ipts_eds1_switch_mode(ipts, buffer[1]); -+ } else { -+ return -EIO; -+ } -+ -+ return ret; -+} -diff --git a/drivers/hid/ipts/eds1.h b/drivers/hid/ipts/eds1.h -new file mode 100644 -index 000000000000..eeeb6575e3e8 ---- /dev/null -+++ b/drivers/hid/ipts/eds1.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include <linux/hid.h> -+#include <linux/types.h> -+ -+#include "context.h" -+ -+/** -+ * ipts_eds1_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds1_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds1_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ 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..e835b460aa79 ---- /dev/null -+++ b/drivers/hid/ipts/eds2.c -@@ -0,0 +1,144 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include <linux/completion.h> -+#include <linux/err.h> -+#include <linux/gfp.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+#include <linux/types.h> -+ -+#include "context.h" -+#include "control.h" -+#include "desc.h" -+#include "spec-data.h" -+ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size) -+{ -+ size_t size = 0; -+ u8 *buffer = NULL; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!desc_buffer) -+ return -EFAULT; -+ -+ if (!desc_size) -+ return -EFAULT; -+ -+ size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; -+ -+ buffer = kzalloc(size, GFP_KERNEL); -+ if (!*buffer) -+ return -ENOMEM; -+ -+ memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -+ ipts->descriptor.size); -+ -+ *desc_size = size; -+ *desc_buffer = buffer; -+ -+ return 0; -+} -+ -+static int ipts_eds2_get_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ mutex_lock(&ipts->feature_lock); -+ -+ memset(buffer, 0, size); -+ buffer[0] = report_id; -+ -+ memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -+ reinit_completion(&ipts->feature_event); -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ goto out; -+ } -+ -+ ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -+ if (ret == 0) { -+ dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -+ ret = -EIO; -+ goto out; -+ } -+ -+ if (!ipts->feature_report.address) { -+ ret = -EFAULT; -+ goto out; -+ } -+ -+ if (ipts->feature_report.size > size) { -+ ret = -ETOOSMALL; -+ goto out; -+ } -+ -+ ret = ipts->feature_report.size; -+ memcpy(buffer, ipts->feature_report.address, ipts->feature_report.size); -+ -+out: -+ mutex_unlock(&ipts->feature_lock); -+ return ret; -+} -+ -+static int ipts_eds2_set_feature(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum ipts_feedback_data_type type) -+{ -+ int ret = 0; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ buffer[0] = report_id; -+ -+ ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buffer, size); -+ if (ret) -+ dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -+ -+ return ret; -+} -+ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ enum hid_report_type report_type, enum hid_class_request request_type) -+{ -+ enum ipts_feedback_data_type feedback_type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -+ -+ if (!ipts) -+ return -EFAULT; -+ -+ if (!buffer) -+ return -EFAULT; -+ -+ if (report_type == HID_OUTPUT_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_GET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -+ else if (report_type == HID_FEATURE_REPORT && request_type == HID_REQ_SET_REPORT) -+ feedback_type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -+ else -+ return -EIO; -+ -+ if (request_type == HID_REQ_GET_REPORT) -+ return ipts_eds2_get_feature(ipts, buffer, report_id, size, feedback_type); -+ else -+ return ipts_eds2_set_feature(ipts, buffer, report_id, size, feedback_type); -+} -diff --git a/drivers/hid/ipts/eds2.h b/drivers/hid/ipts/eds2.h -new file mode 100644 -index 000000000000..064e3716907a ---- /dev/null -+++ b/drivers/hid/ipts/eds2.h -@@ -0,0 +1,35 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Copyright (c) 2023 Dorian Stoll -+ * -+ * Linux driver for Intel Precise Touch & Stylus -+ */ -+ -+#include <linux/hid.h> -+#include <linux/types.h> -+ -+#include "context.h" -+ -+/** -+ * ipts_eds2_get_descriptor() - Assembles the HID descriptor of the device. -+ * @ipts: The IPTS driver context. -+ * @desc_buffer: A pointer to the location where the address of the allocated buffer is stored. -+ * @desc_size: A pointer to the location where the size of the allocated buffer is stored. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t *desc_size); -+ -+/** -+ * ipts_eds2_raw_request() - Executes an output or feature report on the device. -+ * @ipts: The IPTS driver context. -+ * @buffer: The buffer containing the report. -+ * @size: The size of the buffer. -+ * @report_id: The HID report ID. -+ * @report_type: Whether this report is an output or a feature report. -+ * @request_type: Whether this report requests or sends data. -+ * -+ * Returns: 0 on success, <0 on error. -+ */ -+int ipts_eds2_raw_request(struct ipts_context *ipts, u8 *buffer, size_t size, u8 report_id, -+ 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 -index a2471219615b..e34a1a4f9fa7 100644 ---- a/drivers/hid/ipts/hid.c -+++ b/drivers/hid/ipts/hid.c -@@ -1,12 +1,12 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2022-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus - */ - - #include <linux/completion.h> -+#include <linux/err.h> - #include <linux/gfp.h> - #include <linux/hid.h> - #include <linux/mutex.h> -@@ -14,38 +14,30 @@ - #include <linux/types.h> - - #include "context.h" --#include "control.h" - #include "desc.h" -+#include "eds1.h" -+#include "eds2.h" - #include "hid.h" - #include "spec-data.h" --#include "spec-device.h" - #include "spec-hid.h" - --static int ipts_hid_start(struct hid_device *hid) -+void ipts_hid_enable(struct ipts_context *ipts) - { -- return 0; -+ WRITE_ONCE(ipts->hid_active, true); - } - --static void ipts_hid_stop(struct hid_device *hid) -+void ipts_hid_disable(struct ipts_context *ipts) - { -+ WRITE_ONCE(ipts->hid_active, false); - } - --static int ipts_hid_switch_mode(struct ipts_context *ipts, enum ipts_mode mode) -+static int ipts_hid_start(struct hid_device *hid) - { -- if (!ipts) -- return -EFAULT; -- -- if (ipts->mode == mode) -- return 0; -- -- /* -- * This is only allowed on older devices. -- */ -- if (ipts->info.intf_eds > 1) -- return 0; -+ return 0; -+} - -- ipts->mode = mode; -- return ipts_control_restart(ipts); -+static void ipts_hid_stop(struct hid_device *hid) -+{ - } - - static int ipts_hid_parse(struct hid_device *hid) -@@ -53,8 +45,6 @@ static int ipts_hid_parse(struct hid_device *hid) - int ret = 0; - struct ipts_context *ipts = NULL; - -- bool has_native_descriptor = false; -- - u8 *buffer = NULL; - size_t size = 0; - -@@ -66,26 +56,17 @@ static int ipts_hid_parse(struct hid_device *hid) - if (!ipts) - return -EFAULT; - -- size = sizeof(ipts_singletouch_descriptor); -- has_native_descriptor = ipts->descriptor.address && ipts->descriptor.size > 0; -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; - -- if (has_native_descriptor) -- size += ipts->descriptor.size; -+ if (ipts->info.intf_eds == 1) -+ ret = ipts_eds1_get_descriptor(ipts, &buffer, &size); - else -- size += sizeof(ipts_fallback_descriptor); -- -- buffer = kzalloc(size, GFP_KERNEL); -- if (!buffer) -- return -ENOMEM; -- -- memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); -+ ret = ipts_eds2_get_descriptor(ipts, &buffer, &size); - -- if (has_native_descriptor) { -- memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts->descriptor.address, -- ipts->descriptor.size); -- } else { -- memcpy(&buffer[sizeof(ipts_singletouch_descriptor)], ipts_fallback_descriptor, -- sizeof(ipts_fallback_descriptor)); -+ if (ret) { -+ dev_err(ipts->dev, "Failed to allocate HID descriptor: %d\n", ret); -+ return ret; - } - - ret = hid_parse_report(hid, buffer, size); -@@ -99,84 +80,11 @@ static int ipts_hid_parse(struct hid_device *hid) - return 0; - } - --static int ipts_hid_get_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf, -- size_t size, enum ipts_feedback_data_type type) --{ -- int ret = 0; -- -- if (!ipts) -- return -EFAULT; -- -- if (!buf) -- return -EFAULT; -- -- mutex_lock(&ipts->feature_lock); -- -- memset(buf, 0, size); -- buf[0] = reportnum; -- -- memset(&ipts->feature_report, 0, sizeof(ipts->feature_report)); -- reinit_completion(&ipts->feature_event); -- -- ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size); -- if (ret) { -- dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -- goto out; -- } -- -- ret = wait_for_completion_timeout(&ipts->feature_event, msecs_to_jiffies(5000)); -- if (ret == 0) { -- dev_warn(ipts->dev, "GET_FEATURES timed out!\n"); -- ret = -EIO; -- goto out; -- } -- -- if (!ipts->feature_report.address) { -- ret = -EFAULT; -- goto out; -- } -- -- if (ipts->feature_report.size > size) { -- ret = -ETOOSMALL; -- goto out; -- } -- -- ret = ipts->feature_report.size; -- memcpy(buf, ipts->feature_report.address, ipts->feature_report.size); -- --out: -- mutex_unlock(&ipts->feature_lock); -- return ret; --} -- --static int ipts_hid_set_feature(struct ipts_context *ipts, unsigned char reportnum, __u8 *buf, -- size_t size, enum ipts_feedback_data_type type) --{ -- int ret = 0; -- -- if (!ipts) -- return -EFAULT; -- -- if (!buf) -- return -EFAULT; -- -- buf[0] = reportnum; -- -- ret = ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, type, buf, size); -- if (ret) -- dev_err(ipts->dev, "Failed to send hid2me feedback: %d\n", ret); -- -- return ret; --} -- --static int ipts_hid_raw_request(struct hid_device *hid, unsigned char reportnum, __u8 *buf, -- size_t size, unsigned char rtype, int reqtype) -+static int ipts_hid_raw_request(struct hid_device *hid, unsigned char report_id, __u8 *buffer, -+ size_t size, unsigned char report_type, int request_type) - { -- int ret = 0; - struct ipts_context *ipts = NULL; - -- enum ipts_feedback_data_type type = IPTS_FEEDBACK_DATA_TYPE_VENDOR; -- - if (!hid) - return -ENODEV; - -@@ -185,44 +93,16 @@ static int ipts_hid_raw_request(struct hid_device *hid, unsigned char reportnum, - if (!ipts) - return -EFAULT; - -- if (!buf) -- return -EFAULT; -- -- if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) -- type = IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT; -- else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_GET_REPORT) -- type = IPTS_FEEDBACK_DATA_TYPE_GET_FEATURES; -- else if (rtype == HID_FEATURE_REPORT && reqtype == HID_REQ_SET_REPORT) -- type = IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES; -- else -- return -EIO; -- -- // Implemente mode switching report for older devices without native HID support -- if (type == IPTS_FEEDBACK_DATA_TYPE_SET_FEATURES && reportnum == IPTS_HID_REPORT_SET_MODE) { -- ret = ipts_hid_switch_mode(ipts, buf[1]); -- if (ret) { -- dev_err(ipts->dev, "Failed to switch modes: %d\n", ret); -- return ret; -- } -- } -- -- if (reqtype == HID_REQ_GET_REPORT) -- return ipts_hid_get_feature(ipts, reportnum, buf, size, type); -- else -- return ipts_hid_set_feature(ipts, reportnum, buf, size, type); --} -- --static int ipts_hid_output_report(struct hid_device *hid, __u8 *data, size_t size) --{ -- struct ipts_context *ipts = NULL; -- -- if (!hid) -+ if (!READ_ONCE(ipts->hid_active)) - return -ENODEV; - -- ipts = hid->driver_data; -- -- return ipts_control_hid2me_feedback(ipts, IPTS_FEEDBACK_CMD_TYPE_NONE, -- IPTS_FEEDBACK_DATA_TYPE_OUTPUT_REPORT, data, size); -+ if (ipts->info.intf_eds == 1) { -+ return ipts_eds1_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } else { -+ return ipts_eds2_raw_request(ipts, buffer, size, report_id, report_type, -+ request_type); -+ } - } - - static struct hid_ll_driver ipts_hid_driver = { -@@ -232,7 +112,6 @@ static struct hid_ll_driver ipts_hid_driver = { - .close = ipts_hid_stop, - .parse = ipts_hid_parse, - .raw_request = ipts_hid_raw_request, -- .output_report = ipts_hid_output_report, - }; - - int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) -@@ -247,6 +126,9 @@ int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer) - if (!ipts->hid) - return -ENODEV; - -+ if (!READ_ONCE(ipts->hid_active)) -+ return -ENODEV; -+ - header = (struct ipts_data_header *)ipts->resources.data[buffer].address; - - temp = ipts->resources.report.address; -diff --git a/drivers/hid/ipts/hid.h b/drivers/hid/ipts/hid.h -index 62bf3cd48608..1ebe77447903 100644 ---- a/drivers/hid/ipts/hid.h -+++ b/drivers/hid/ipts/hid.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2022-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -14,6 +13,9 @@ - #include "context.h" - #include "spec-device.h" - -+void ipts_hid_enable(struct ipts_context *ipts); -+void ipts_hid_disable(struct ipts_context *ipts); -+ - int ipts_hid_input_data(struct ipts_context *ipts, u32 buffer); - - int ipts_hid_init(struct ipts_context *ipts, struct ipts_device_info info); -diff --git a/drivers/hid/ipts/main.c b/drivers/hid/ipts/main.c -index 0f20c6c08c38..fb5b5c13ee3e 100644 ---- a/drivers/hid/ipts/main.c -+++ b/drivers/hid/ipts/main.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/mei.c b/drivers/hid/ipts/mei.c -index 26666fd99b0c..1e0395ceae4a 100644 ---- a/drivers/hid/ipts/mei.c -+++ b/drivers/hid/ipts/mei.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/mei.h b/drivers/hid/ipts/mei.h -index eadacae54c40..973bade6b0fd 100644 ---- a/drivers/hid/ipts/mei.h -+++ b/drivers/hid/ipts/mei.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -31,7 +30,7 @@ struct ipts_mei { - struct rw_semaphore message_lock; - }; - --/* -+/** - * ipts_mei_recv() - Receive data from a MEI device. - * @mei: The IPTS MEI device context. - * @code: The IPTS command code to look for. -@@ -45,7 +44,7 @@ struct ipts_mei { - int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts_response *rsp, - u64 timeout); - --/* -+/** - * ipts_mei_send() - Send data to a MEI device. - * @ipts: The IPTS MEI device context. - * @data: The data to send. -@@ -55,7 +54,7 @@ int ipts_mei_recv(struct ipts_mei *mei, enum ipts_command_code code, struct ipts - */ - int ipts_mei_send(struct ipts_mei *mei, void *data, size_t length); - --/* -+/** - * ipts_mei_init() - Initialize the MEI device context. - * @mei: The MEI device context to initialize. - * @cldev: The MEI device the context will be bound to. -diff --git a/drivers/hid/ipts/receiver.c b/drivers/hid/ipts/receiver.c -index f56e9ed32d57..ef66c3c9db80 100644 ---- a/drivers/hid/ipts/receiver.c -+++ b/drivers/hid/ipts/receiver.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -66,7 +65,9 @@ static int ipts_receiver_event_loop(struct ipts_thread *thread) - dev_info(ipts->dev, "IPTS running in event mode\n"); - - while (!ipts_thread_should_stop(thread)) { -- for (int i = 0; i < IPTS_BUFFERS; i++) { -+ int i = 0; -+ -+ for (i = 0; i < IPTS_BUFFERS; i++) { - ret = ipts_control_wait_data(ipts, false); - if (ret == -EAGAIN) - break; -@@ -126,7 +127,7 @@ static int ipts_receiver_event_loop(struct ipts_thread *thread) - return 0; - } - --static int ipts_receiver_doorbell_loop(struct ipts_thread *thread) -+static int ipts_receiver_poll_loop(struct ipts_thread *thread) - { - int ret = 0; - u32 buffer = 0; -@@ -145,7 +146,7 @@ static int ipts_receiver_doorbell_loop(struct ipts_thread *thread) - if (!ipts) - return -EFAULT; - -- dev_info(ipts->dev, "IPTS running in doorbell mode\n"); -+ dev_info(ipts->dev, "IPTS running in poll mode\n"); - - while (true) { - if (ipts_thread_should_stop(thread)) { -@@ -217,9 +218,9 @@ int ipts_receiver_start(struct ipts_context *ipts) - if (ipts->mode == IPTS_MODE_EVENT) { - ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_event_loop, ipts, - "ipts_event"); -- } else if (ipts->mode == IPTS_MODE_DOORBELL) { -- ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_doorbell_loop, ipts, -- "ipts_doorbell"); -+ } else if (ipts->mode == IPTS_MODE_POLL) { -+ ret = ipts_thread_start(&ipts->receiver_loop, ipts_receiver_poll_loop, ipts, -+ "ipts_poll"); - } else { - ret = -EINVAL; - } -diff --git a/drivers/hid/ipts/receiver.h b/drivers/hid/ipts/receiver.h -index 96070f34fbca..3de7da62d40c 100644 ---- a/drivers/hid/ipts/receiver.h -+++ b/drivers/hid/ipts/receiver.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/resources.c b/drivers/hid/ipts/resources.c -index 5e924d58c488..cc14653b2a9f 100644 ---- a/drivers/hid/ipts/resources.c -+++ b/drivers/hid/ipts/resources.c -@@ -1,12 +1,12 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus - */ - - #include <linux/dma-mapping.h> -+#include <linux/slab.h> - #include <linux/types.h> - - #include "desc.h" -@@ -107,10 +107,6 @@ int ipts_resources_init(struct ipts_resources *res, struct device *dev, size_t d - - int ipts_resources_free(struct ipts_resources *res) - { -- /* -- * Some compilers (AOSP clang) complain about a redefined -- * variable when this is declared inside of the for loop. -- */ - int i = 0; - - if (!res) -diff --git a/drivers/hid/ipts/resources.h b/drivers/hid/ipts/resources.h -index e0c400f420b9..2068e13285f0 100644 ---- a/drivers/hid/ipts/resources.h -+++ b/drivers/hid/ipts/resources.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/spec-device.h b/drivers/hid/ipts/spec-device.h -index 93f673d981f7..41845f9d9025 100644 ---- a/drivers/hid/ipts/spec-device.h -+++ b/drivers/hid/ipts/spec-device.h -@@ -109,14 +109,14 @@ static_assert(sizeof(struct ipts_command) == 324); - - /** - * enum ipts_mode - Configures what data the device produces and how its sent. -- * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -- * Older devices will return singletouch data in this mode. -- * @IPTS_MODE_DOORBELL: The device will notify the driver by incrementing the doorbell value. -- * Older devices will return multitouch data in this mode. -+ * @IPTS_MODE_EVENT: The device will send an event once a buffer was filled. -+ * Older devices will return singletouch data in this mode. -+ * @IPTS_MODE_POLL: The device will notify the driver by incrementing the doorbell value. -+ * Older devices will return multitouch data in this mode. - */ - enum ipts_mode { - IPTS_MODE_EVENT = 0x00, -- IPTS_MODE_DOORBELL = 0x01, -+ IPTS_MODE_POLL = 0x01, - }; - - /** -@@ -253,14 +253,19 @@ static_assert(sizeof(struct ipts_response) == 88); - - /** - * struct ipts_device_info - Vendor information of the IPTS device. -- * @vendor: Vendor ID of this device. -- * @product: Product ID of this device. -- * @hw_version: Hardware revision of this device. -- * @fw_version: Firmware revision of this device. -- * @data_size: Requested size for a data buffer. -- * @feedback_size: Requested size for a feedback buffer. -- * @mode: Mode that the device currently operates in. -- * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @vendor: Vendor ID of this device. -+ * @product: Product ID of this device. -+ * @hw_version: Hardware revision of this device. -+ * @fw_version: Firmware revision of this device. -+ * @data_size: Requested size for a data buffer. -+ * @feedback_size: Requested size for a feedback buffer. -+ * @mode: Mode that the device currently operates in. -+ * @max_contacts: Maximum amount of concurrent touches the sensor can process. -+ * @sensor_min_eds: The minimum EDS version supported by the sensor. -+ * @sensor_max_eds: The maximum EDS version supported by the sensor. -+ * @me_min_eds: The minimum EDS version supported by the ME for communicating with the sensor. -+ * @me_max_eds: The maximum EDS version supported by the ME for communicating with the sensor. -+ * @intf_eds: The EDS version implemented by the interface between ME and host. - */ - struct ipts_device_info { - u16 vendor; -diff --git a/drivers/hid/ipts/spec-hid.h b/drivers/hid/ipts/spec-hid.h -index ea70f29ff00c..5a58d4a0a610 100644 ---- a/drivers/hid/ipts/spec-hid.h -+++ b/drivers/hid/ipts/spec-hid.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2020-2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/thread.c b/drivers/hid/ipts/thread.c -index 8b46f775c107..355e92bea26f 100644 ---- a/drivers/hid/ipts/thread.c -+++ b/drivers/hid/ipts/thread.c -@@ -1,6 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -diff --git a/drivers/hid/ipts/thread.h b/drivers/hid/ipts/thread.h -index a314843599fc..1f966b8b32c4 100644 ---- a/drivers/hid/ipts/thread.h -+++ b/drivers/hid/ipts/thread.h -@@ -1,6 +1,5 @@ - /* SPDX-License-Identifier: GPL-2.0-or-later */ - /* -- * Copyright (c) 2016 Intel Corporation - * Copyright (c) 2023 Dorian Stoll - * - * Linux driver for Intel Precise Touch & Stylus -@@ -29,7 +28,7 @@ struct ipts_thread { - int (*threadfn)(struct ipts_thread *thread); - }; - --/* -+/** - * ipts_thread_should_stop() - Returns true if the thread is asked to terminate. - * @thread: The current thread. - * -@@ -37,7 +36,7 @@ struct ipts_thread { - */ - bool ipts_thread_should_stop(struct ipts_thread *thread); - --/* -+/** - * ipts_thread_start() - Starts an IPTS thread. - * @thread: The thread to initialize and start. - * @threadfn: The function to execute. -@@ -49,7 +48,7 @@ bool ipts_thread_should_stop(struct ipts_thread *thread); - int ipts_thread_start(struct ipts_thread *thread, int (*threadfn)(struct ipts_thread *thread), - void *data, const char name[]); - --/* -+/** - * ipts_thread_stop() - Asks the thread to terminate and waits until it has finished. - * @thread: The thread that should stop. - * --- -2.41.0 - -From 076482103071f96815dea8ef9da74b8cf6a642ae Mon Sep 17 00:00:00 2001 -From: Dorian Stoll <dorian.stoll@tmsp.io> -Date: Sat, 22 Jul 2023 17:08:56 +0200 -Subject: [PATCH] Update IPTS from module repo - -Changes: - * Fix allocating the HID descriptor on EDS v2 - -Idk why I wrote that, for EDS v1 I got it right ... - -Based on https://github.com/linux-surface/intel-precise-touch/commit/32622a37f27113067a6c9aff21627859caab43f9 - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ipts ---- - drivers/hid/ipts/eds2.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/hid/ipts/eds2.c b/drivers/hid/ipts/eds2.c -index e835b460aa79..7c5cbafdb279 100644 ---- a/drivers/hid/ipts/eds2.c -+++ b/drivers/hid/ipts/eds2.c -@@ -34,7 +34,7 @@ int ipts_eds2_get_descriptor(struct ipts_context *ipts, u8 **desc_buffer, size_t - size = sizeof(ipts_singletouch_descriptor) + ipts->descriptor.size; - - buffer = kzalloc(size, GFP_KERNEL); -- if (!*buffer) -+ if (!buffer) - return -ENOMEM; - - memcpy(buffer, ipts_singletouch_descriptor, sizeof(ipts_singletouch_descriptor)); --- -2.41.0 - -From c9650eca17f7f7dbd6ea1cfe8a33a30bc00f011f 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 - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ithc ---- - drivers/iommu/intel/irq_remapping.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c -index a1b987335b31..970805409470 100644 ---- a/drivers/iommu/intel/irq_remapping.c -+++ b/drivers/iommu/intel/irq_remapping.c -@@ -390,6 +390,22 @@ static int set_msi_sid(struct irte *irte, struct pci_dev *dev) - data.busmatch_count = 0; - pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - -+ /* -+ * The Intel Touch Host Controller is at 00:10.6, but for some reason -+ * the MSI interrupts have request id 01:05.0. -+ * Disable id verification to work around this. -+ * FIXME Find proper fix or turn this into a quirk. -+ */ -+ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { -+ switch(dev->device) { -+ case 0x98d0: case 0x98d1: // LKF -+ case 0xa0d0: case 0xa0d1: // TGL LP -+ case 0x43d0: case 0x43d1: // TGL H -+ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); -+ return 0; -+ } -+ } -+ - /* - * 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.41.0 - -From 6e9262732447276e2e1a19da7701bd32da622ea0 Mon Sep 17 00:00:00 2001 -From: Dorian Stoll <dorian.stoll@tmsp.io> -Date: Sun, 11 Dec 2022 12:10:54 +0100 -Subject: [PATCH] hid: Add support for Intel Touch Host Controller - -Based on quo/ithc-linux@55803a2 - -Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io> -Patchset: ithc ---- - drivers/hid/Kconfig | 2 + - drivers/hid/Makefile | 1 + - drivers/hid/ithc/Kbuild | 6 + - drivers/hid/ithc/Kconfig | 12 + - drivers/hid/ithc/ithc-debug.c | 96 ++++++ - drivers/hid/ithc/ithc-dma.c | 258 ++++++++++++++++ - drivers/hid/ithc/ithc-dma.h | 67 +++++ - drivers/hid/ithc/ithc-main.c | 534 ++++++++++++++++++++++++++++++++++ - drivers/hid/ithc/ithc-regs.c | 64 ++++ - drivers/hid/ithc/ithc-regs.h | 186 ++++++++++++ - drivers/hid/ithc/ithc.h | 60 ++++ - 11 files changed, 1286 insertions(+) - create mode 100644 drivers/hid/ithc/Kbuild - create mode 100644 drivers/hid/ithc/Kconfig - create mode 100644 drivers/hid/ithc/ithc-debug.c - create mode 100644 drivers/hid/ithc/ithc-dma.c - create mode 100644 drivers/hid/ithc/ithc-dma.h - create mode 100644 drivers/hid/ithc/ithc-main.c - create mode 100644 drivers/hid/ithc/ithc-regs.c - create mode 100644 drivers/hid/ithc/ithc-regs.h - create mode 100644 drivers/hid/ithc/ithc.h - -diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig -index 7945cb57f531..91e9e4f58c27 100644 ---- a/drivers/hid/Kconfig -+++ b/drivers/hid/Kconfig -@@ -1318,4 +1318,6 @@ source "drivers/hid/surface-hid/Kconfig" - - source "drivers/hid/ipts/Kconfig" - -+source "drivers/hid/ithc/Kconfig" -+ - endif # HID_SUPPORT -diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile -index 285e12d95b0e..a3ff62e922f1 100644 ---- a/drivers/hid/Makefile -+++ b/drivers/hid/Makefile -@@ -169,3 +169,4 @@ obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ - obj-$(CONFIG_SURFACE_HID_CORE) += surface-hid/ - - obj-$(CONFIG_HID_IPTS) += ipts/ -+obj-$(CONFIG_HID_ITHC) += ithc/ diff --git a/drivers/hid/ithc/Kbuild b/drivers/hid/ithc/Kbuild new file mode 100644 -index 000000000000..aea83f2ac07b +index 000000000..aea83f2ac --- /dev/null +++ b/drivers/hid/ithc/Kbuild @@ -0,0 +1,6 @@ @@ -5196,7 +3734,7 @@ index 000000000000..aea83f2ac07b + diff --git a/drivers/hid/ithc/Kconfig b/drivers/hid/ithc/Kconfig new file mode 100644 -index 000000000000..ede713023609 +index 000000000..ede713023 --- /dev/null +++ b/drivers/hid/ithc/Kconfig @@ -0,0 +1,12 @@ @@ -5214,7 +3752,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..57bf125c45bd +index 000000000..57bf125c4 --- /dev/null +++ b/drivers/hid/ithc/ithc-debug.c @@ -0,0 +1,96 @@ @@ -5316,7 +3854,7 @@ index 000000000000..57bf125c45bd + diff --git a/drivers/hid/ithc/ithc-dma.c b/drivers/hid/ithc/ithc-dma.c new file mode 100644 -index 000000000000..7e89b3496918 +index 000000000..7e89b3496 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.c @@ -0,0 +1,258 @@ @@ -5580,7 +4118,7 @@ index 000000000000..7e89b3496918 + diff --git a/drivers/hid/ithc/ithc-dma.h b/drivers/hid/ithc/ithc-dma.h new file mode 100644 -index 000000000000..d9f2c19a13f3 +index 000000000..d9f2c19a1 --- /dev/null +++ b/drivers/hid/ithc/ithc-dma.h @@ -0,0 +1,67 @@ @@ -5653,7 +4191,7 @@ index 000000000000..d9f2c19a13f3 + diff --git a/drivers/hid/ithc/ithc-main.c b/drivers/hid/ithc/ithc-main.c new file mode 100644 -index 000000000000..09512b9cb4d3 +index 000000000..09512b9cb --- /dev/null +++ b/drivers/hid/ithc/ithc-main.c @@ -0,0 +1,534 @@ @@ -6193,7 +4731,7 @@ index 000000000000..09512b9cb4d3 + diff --git a/drivers/hid/ithc/ithc-regs.c b/drivers/hid/ithc/ithc-regs.c new file mode 100644 -index 000000000000..85d567b05761 +index 000000000..85d567b05 --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.c @@ -0,0 +1,64 @@ @@ -6263,7 +4801,7 @@ index 000000000000..85d567b05761 + diff --git a/drivers/hid/ithc/ithc-regs.h b/drivers/hid/ithc/ithc-regs.h new file mode 100644 -index 000000000000..1a96092ed7ee +index 000000000..1a96092ed --- /dev/null +++ b/drivers/hid/ithc/ithc-regs.h @@ -0,0 +1,186 @@ @@ -6455,7 +4993,7 @@ index 000000000000..1a96092ed7ee + diff --git a/drivers/hid/ithc/ithc.h b/drivers/hid/ithc/ithc.h new file mode 100644 -index 000000000000..6a9b0d480bc1 +index 000000000..6a9b0d480 --- /dev/null +++ b/drivers/hid/ithc/ithc.h @@ -0,0 +1,60 @@ @@ -6519,67 +5057,8 @@ index 000000000000..6a9b0d480bc1 +int ithc_debug_init(struct ithc *ithc); +void ithc_log_regs(struct ithc *ithc); + --- -2.41.0 - -From e87bc8644c1f6241309562a27b3d2f5b34054db1 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 - -Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C -device via a generic serial bus operation region and RawBytes read -access. On the Surface Book 1, this access is required to turn on (and -off) the discrete GPU. - -Multiple things are to note here: - -a) The RawBytes access is device/driver dependent. The ACPI - specification states: - - > Raw accesses assume that the writer has knowledge of the bus that - > the access is made over and the device that is being accessed. The - > protocol may only ensure that the buffer is transmitted to the - > appropriate driver, but the driver must be able to interpret the - > buffer to communicate to a register. - - Thus this implementation may likely not work on other devices - accessing I2C via the RawBytes accessor type. - -b) The MSHW0030 I2C device is an HID-over-I2C device which seems to - serve multiple functions: - - 1. It is the main access point for the legacy-type Surface Aggregator - Module (also referred to as SAM-over-HID, as opposed to the newer - SAM-over-SSH/UART). It has currently not been determined on how - support for the legacy SAM should be implemented. Likely via a - custom HID driver. - - 2. It seems to serve as the HID device for the Integrated Sensor Hub. - This might complicate matters with regards to implementing a - SAM-over-HID driver required by legacy SAM. - -In light of this, the simplest approach has been chosen for now. -However, it may make more sense regarding breakage and compatibility to -either provide functionality for replacing or enhancing the default -operation region handler via some additional API functions, or even to -completely blacklist MSHW0030 from the I2C core and provide a custom -driver for it. - -Replacing/enhancing the default operation region handler would, however, -either require some sort of secondary driver and access point for it, -from which the new API functions would be called and the new handler -(part) would be installed, or hard-coding them via some sort of -quirk-like interface into the I2C core. - -Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: surface-sam-over-hid ---- - drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ - 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 d6037a328..a290ebc77 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, @@ -6631,255 +5110,8 @@ index d6037a328669..a290ebc77aea 100644 default: dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); --- -2.41.0 - -From 94fe2b2dccbbec57753b3c0750607a650c14b4b9 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 - -Add driver exposing the discrete GPU power-switch of the Microsoft -Surface Book 1 to user-space. - -On the Surface Book 1, the dGPU power is controlled via the Surface -System Aggregator Module (SAM). The specific SAM-over-HID command for -this is exposed via ACPI. This module provides a simple driver exposing -the ACPI call via a sysfs parameter to user-space, so that users can -easily power-on/-off the dGPU. - -Patchset: surface-sam-over-hid ---- - drivers/platform/surface/Kconfig | 7 + - drivers/platform/surface/Makefile | 1 + - .../surface/surfacebook1_dgpu_switch.c | 162 ++++++++++++++++++ - 3 files changed, 170 insertions(+) - 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 ---- a/drivers/platform/surface/Kconfig -+++ b/drivers/platform/surface/Kconfig -@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH - Select M or Y here, if you want to provide tablet-mode switch input - events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. - -+config SURFACE_BOOK1_DGPU_SWITCH -+ tristate "Surface Book 1 dGPU Switch Driver" -+ depends on SYSFS -+ help -+ This driver provides a sysfs switch to set the power-state of the -+ discrete GPU found on the Microsoft Surface Book 1. -+ - config SURFACE_DTX - 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 ---- a/drivers/platform/surface/Makefile -+++ b/drivers/platform/surface/Makefile -@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o - obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o - obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o - obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o -+obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o - obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o - obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o - 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 ---- /dev/null -+++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c -@@ -0,0 +1,162 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/acpi.h> -+#include <linux/platform_device.h> -+ -+ -+#ifdef pr_fmt -+#undef pr_fmt -+#endif -+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ -+ -+ -+static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, -+ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); -+ -+#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" -+#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" -+#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" -+ -+ -+static int sb1_dgpu_sw_dsmcall(void) -+{ -+ union acpi_object *ret; -+ acpi_handle handle; -+ acpi_status status; -+ -+ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); -+ if (status) -+ return -EINVAL; -+ -+ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); -+ if (!ret) -+ return -EINVAL; -+ -+ ACPI_FREE(ret); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgon(void) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); -+ if (status) { -+ pr_err("failed to run HGON: %d\n", status); -+ return -EINVAL; -+ } -+ -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); -+ -+ pr_info("turned-on dGPU via HGON\n"); -+ return 0; -+} -+ -+static int sb1_dgpu_sw_hgof(void) -+{ -+ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; -+ acpi_status status; -+ -+ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); -+ if (status) { -+ pr_err("failed to run HGOF: %d\n", status); -+ return -EINVAL; -+ } -+ -+ if (buf.pointer) -+ ACPI_FREE(buf.pointer); -+ -+ pr_info("turned-off dGPU via HGOF\n"); -+ return 0; -+} -+ -+ -+static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int status, value; -+ -+ status = kstrtoint(buf, 0, &value); -+ if (status < 0) -+ return status; -+ -+ if (value != 1) -+ return -EINVAL; -+ -+ status = sb1_dgpu_sw_dsmcall(); -+ -+ return status < 0 ? status : len; -+} -+ -+static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ bool power; -+ int status; -+ -+ status = kstrtobool(buf, &power); -+ if (status < 0) -+ return status; -+ -+ if (power) -+ status = sb1_dgpu_sw_hgon(); -+ else -+ status = sb1_dgpu_sw_hgof(); -+ -+ return status < 0 ? status : len; -+} -+ -+static DEVICE_ATTR_WO(dgpu_dsmcall); -+static DEVICE_ATTR_WO(dgpu_power); -+ -+static struct attribute *sb1_dgpu_sw_attrs[] = { -+ &dev_attr_dgpu_dsmcall.attr, -+ &dev_attr_dgpu_power.attr, -+ NULL, -+}; -+ -+static const struct attribute_group sb1_dgpu_sw_attr_group = { -+ .attrs = sb1_dgpu_sw_attrs, -+}; -+ -+ -+static int sb1_dgpu_sw_probe(struct platform_device *pdev) -+{ -+ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+} -+ -+static int sb1_dgpu_sw_remove(struct platform_device *pdev) -+{ -+ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); -+ return 0; -+} -+ -+/* -+ * The dGPU power seems to be actually handled by MSHW0040. However, that is -+ * also the power-/volume-button device with a mainline driver. So let's use -+ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. -+ */ -+static const struct acpi_device_id sb1_dgpu_sw_match[] = { -+ { "MSHW0041", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); -+ -+static struct platform_driver sb1_dgpu_sw = { -+ .probe = sb1_dgpu_sw_probe, -+ .remove = sb1_dgpu_sw_remove, -+ .driver = { -+ .name = "surfacebook1_dgpu_switch", -+ .acpi_match_table = sb1_dgpu_sw_match, -+ .probe_type = PROBE_PREFER_ASYNCHRONOUS, -+ }, -+}; -+module_platform_driver(sb1_dgpu_sw); -+ -+MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); -+MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); -+MODULE_LICENSE("GPL"); --- -2.41.0 - -From c0dbaf869d5119db6838d1fe66f9e06136f69c42 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 - -The power button on the AMD variant of the Surface Laptop uses the -same MSHW0040 device ID as the 5th and later generation of Surface -devices, however they report 0 for their OEM platform revision. As the -_DSM does not exist on the devices requiring special casing, check for -the existance of the _DSM to determine if soc_button_array should be -loaded. - -Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") -Co-developed-by: Maximilian Luz <luzmaximilian@gmail.com> - -Signed-off-by: Sachi King <nakato@nakato.io> -Patchset: surface-button ---- - drivers/input/misc/soc_button_array.c | 33 +++++++-------------------- - 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 e79f5497948b..2bddbe6e9ea4 100644 +index e79f54979..2bddbe6e9 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -537,8 +537,8 @@ static const struct soc_device_data soc_device_MSHW0028 = { @@ -6931,909 +5163,11 @@ index e79f5497948b..2bddbe6e9ea4 100644 } /* --- -2.41.0 - -From f4fe09308d0f8c665b30deaaa42ed60333f135cd 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 - variant - -The AMD variant of the Surface Laptop report 0 for their OEM platform -revision. The Surface devices that require the surfacepro3_button -driver do not have the _DSM that gets the OEM platform revision. If the -method does not exist, load surfacepro3_button. - -Fixes: 64dd243d7356 ("platform/x86: surfacepro3_button: Fix device check") -Co-developed-by: Maximilian Luz <luzmaximilian@gmail.com> - -Signed-off-by: Sachi King <nakato@nakato.io> -Patchset: surface-button ---- - drivers/platform/surface/surfacepro3_button.c | 30 ++++--------------- - 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 ---- 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) - /* - * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device - * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -- * device by checking for the _DSM method and OEM Platform Revision. -+ * device by checking for the _DSM method and OEM Platform Revision DSM -+ * function. - * - * Returns true if the driver should bind to this device, i.e. the device is - * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) - static bool surface_button_check_MSHW0040(struct acpi_device *dev) - { - acpi_handle handle = dev->handle; -- union acpi_object *result; -- u64 oem_platform_rev = 0; // valid revisions are nonzero -- -- // get OEM platform revision -- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -- MSHW0040_DSM_REVISION, -- MSHW0040_DSM_GET_OMPR, -- NULL, ACPI_TYPE_INTEGER); -- -- /* -- * If evaluating the _DSM fails, the method is not present. This means -- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -- * should use this driver. We use revision 0 indicating it is -- * unavailable. -- */ -- -- if (result) { -- oem_platform_rev = result->integer.value; -- ACPI_FREE(result); -- } -- -- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - -- return oem_platform_rev == 0; -+ // make sure that OEM platform revision DSM call does not exist -+ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ BIT(MSHW0040_DSM_GET_OMPR)); - } - - --- -2.41.0 - -From 785f9b97e9da3623421f5c3986b7fa3469641858 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 934b3d997702..2c6604c6e8e1 100644 ---- a/drivers/usb/core/quirks.c -+++ b/drivers/usb/core/quirks.c -@@ -220,6 +220,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.41.0 - -From e4faddc8b5b4dfd88fd766e438d455fb7bbccb8c 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 e31be0cb8b85..63fd042aba6b 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 -+ }, - { } - }; - -@@ -1728,6 +1748,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; -@@ -1751,6 +1834,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); - -@@ -1789,15 +1875,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) -@@ -1849,6 +1939,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); -@@ -2226,6 +2317,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.41.0 - -From e5cadf1b77047bd8f004aaa5571437007e39b39c 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 63fd042aba6b..508a250ff4bf 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); -@@ -1660,6 +1742,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; -@@ -1748,30 +1837,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); -@@ -1780,8 +1845,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; - } -@@ -1916,13 +1982,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. */ -@@ -1931,6 +2008,10 @@ 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; - } - #endif -@@ -1938,6 +2019,21 @@ static int mt_resume(struct hid_device *hdev) - 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.41.0 - -From c12f7cb4d5133c2a8b8eba90f5f011dddae0a3b2 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 - -Work around buggy EFI firmware: On some Microsoft Surface devices -(Surface Pro 9 and Surface Laptop 5) the EFI ResetSystem call with -EFI_RESET_SHUTDOWN doesn't function properly. Instead of shutting the -system down, it returns and the system stays on. - -It turns out that this only happens after PCI shutdown callbacks ran for -specific devices. Excluding those devices from the shutdown process -makes the ResetSystem call work as expected. - -TODO: Maybe we can find a better way or the root cause of this? - -Not-Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: surface-shutdown ---- - drivers/pci/pci-driver.c | 3 +++ - drivers/pci/quirks.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/pci.h | 1 + - 3 files changed, 40 insertions(+) - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index ae9baf801681..fdfaec2312a0 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) - struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *drv = pci_dev->driver; - -+ if (pci_dev->no_shutdown) -+ return; -+ - pm_runtime_resume(dev); - - if (drv && drv->shutdown) -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index c525867760bf..b67d9181a608 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -6041,3 +6041,39 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size); - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size); - #endif -+ -+static const struct dmi_system_id no_shutdown_dmi_table[] = { -+ /* -+ * Systems on which some devices should not be touched during shutdown. -+ */ -+ { -+ .ident = "Microsoft Surface Pro 9", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), -+ }, -+ }, -+ { -+ .ident = "Microsoft Surface Laptop 5", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), -+ }, -+ }, -+ {} -+}; -+ -+static void quirk_no_shutdown(struct pci_dev *dev) -+{ -+ if (!dmi_check_system(no_shutdown_dmi_table)) -+ return; -+ -+ dev->no_shutdown = 1; -+ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", -+ dev->vendor, dev->device); -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port -+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 60b8772b5bd4..cc07be9c7e37 100644 ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -464,6 +464,7 @@ struct pci_dev { - unsigned int no_vf_scan:1; /* Don't scan for VFs after IOV enablement */ - unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ - unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ -+ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - --- -2.41.0 - -From c017d94dbc46d648b52e7ff2f66df960b9c2f130 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 - -Add the lid GPE used by the Surface Pro 9. - -Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: surface-gpe ---- - drivers/platform/surface/surface_gpe.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c -index c219b840d491..69c4352e8406 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[] = { - {}, - }; - -+static const struct property_entry lid_device_props_l52[] = { -+ PROPERTY_ENTRY_U32("gpe", 0x52), -+ {}, -+}; -+ - static const struct property_entry lid_device_props_l57[] = { - PROPERTY_ENTRY_U32("gpe", 0x57), - {}, -@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { - }, - .driver_data = (void *)lid_device_props_l4B, - }, -+ { -+ /* -+ * We match for SKU here due to product name clash with the ARM -+ * version. -+ */ -+ .ident = "Surface Pro 9", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), -+ }, -+ .driver_data = (void *)lid_device_props_l52, -+ }, - { - .ident = "Surface Book 1", - .matches = { --- -2.41.0 - -From d69944e1acb3f417731b5128ba7e9ee1ead0fa8f 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 - INT3472 device - -The clk and regulator frameworks expect clk/regulator consumer-devices -to have info about the consumed clks/regulators described in the device's -fw_node. - -To work around cases where this info is not present in the firmware tables, -which is often the case on x86/ACPI devices, both frameworks allow the -provider-driver to attach info about consumers to the clks/regulators -when registering these. - -This causes problems with the probe ordering wrt drivers for consumers -of these clks/regulators. Since the lookups are only registered when the -provider-driver binds, trying to get these clks/regulators before then -results in a -ENOENT error for clks and a dummy regulator for regulators. - -One case where we hit this issue is camera sensors such as e.g. the OV8865 -sensor found on the Microsoft Surface Go. The sensor uses clks, regulators -and GPIOs provided by a TPS68470 PMIC which is described in an INT3472 -ACPI device. There is special platform code handling this and setting -platform_data with the necessary consumer info on the MFD cells -instantiated for the PMIC under: drivers/platform/x86/intel/int3472. - -For this to work properly the ov8865 driver must not bind to the I2C-client -for the OV8865 sensor until after the TPS68470 PMIC gpio, regulator and -clk MFD cells have all been fully setup. - -The OV8865 on the Microsoft Surface Go is just one example, all X86 -devices using the Intel IPU3 camera block found on recent Intel SoCs -have similar issues where there is an INT3472 HID ACPI-device, which -describes the clks and regulators, and the driver for this INT3472 device -must be fully initialized before the sensor driver (any sensor driver) -binds for things to work properly. - -On these devices the ACPI nodes describing the sensors all have a _DEP -dependency on the matching INT3472 ACPI device (there is one per sensor). - -This allows solving the probe-ordering problem by delaying the enumeration -(instantiation of the I2C-client in the ov8865 example) of ACPI-devices -which have a _DEP dependency on an INT3472 device. - -The new acpi_dev_ready_for_enumeration() helper used for this is also -exported because for devices, which have the enumeration_by_parent flag -set, the parent-driver will do its own scan of child ACPI devices and -it will try to enumerate those during its probe(). Code doing this such -as e.g. the i2c-core-acpi.c code must call this new helper to ensure -that it too delays the enumeration until all the _DEP dependencies are -met on devices which have the new honor_deps flag set. - -Signed-off-by: Hans de Goede <hdegoede@redhat.com> -Patchset: cameras ---- - drivers/acpi/scan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c -index 0c6f06abe3f4..4fc320f424e8 100644 ---- a/drivers/acpi/scan.c -+++ b/drivers/acpi/scan.c -@@ -2106,6 +2106,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) - { -+ if (!acpi_dev_ready_for_enumeration(device)) -+ return; -+ - /* - * Do not enumerate devices with enumeration_by_parent flag set as - * they will be enumerated by their respective parents. --- -2.41.0 - -From 23a732b89e9a9572095ebc9bc6d79d1f6a0b3d81 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 - -Intel IPU(Image Processing Unit) has its own (IO)MMU hardware, -The IPU driver allocates its own page table that is not mapped -via the DMA, and thus the Intel IOMMU driver blocks access giving -this error: DMAR: DRHD: handling fault status reg 3 DMAR: -[DMA Read] Request device [00:05.0] PASID ffffffff -fault addr 76406000 [fault reason 06] PTE Read access is not set -As IPU is not an external facing device which is not risky, so use -IOMMU passthrough mode for Intel IPUs. - -Change-Id: I6dcccdadac308cf42e20a18e1b593381391e3e6b -Depends-On: Iacd67578e8c6a9b9ac73285f52b4081b72fb68a6 -Tracked-On: #JIITL8-411 -Signed-off-by: Bingbu Cao <bingbu.cao@intel.com> -Signed-off-by: zouxiaoh <xiaohong.zou@intel.com> -Signed-off-by: Xu Chongyang <chongyang.xu@intel.com> -Patchset: cameras ---- - drivers/iommu/intel/iommu.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c -index 0d4542b7365d..c96a9baea21c 100644 +index 5c8c5cdc3..e10b4f625 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c -@@ -37,6 +37,12 @@ +@@ -37,6 +37,14 @@ #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) #define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB) #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA) @@ -7843,13 +5177,16 @@ index 0d4542b7365d..c96a9baea21c 100644 + (pdev)->device == 0x4e19 || \ + (pdev)->device == 0x465d || \ + (pdev)->device == 0x1919)) - #define IS_IPTS(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ - ((pdev)->device == 0x9d3e)) ++#define IS_IPTS(pdev) ((pdev)->vendor == PCI_VENDOR_ID_INTEL && \ ++ ((pdev)->device == 0x9d3e)) #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e) -@@ -290,12 +296,14 @@ EXPORT_SYMBOL_GPL(intel_iommu_enabled); + + #define IOAPIC_RANGE_START (0xfee00000) +@@ -287,12 +295,16 @@ 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_ipts = 1; +static int dmar_map_ipu = 1; static int intel_iommu_superpage = 1; static int iommu_identity_mapping; @@ -7858,30 +5195,37 @@ index 0d4542b7365d..c96a9baea21c 100644 #define IDENTMAP_GFX 2 #define IDENTMAP_AZALIA 4 +#define IDENTMAP_IPU 8 - #define IDENTMAP_IPTS 16 ++#define IDENTMAP_IPTS 16 const struct iommu_ops intel_iommu_ops; -@@ -2565,6 +2573,9 @@ static int device_def_domain_type(struct device *dev) + +@@ -2548,6 +2560,12 @@ static int device_def_domain_type(struct device *dev) + if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev)) return IOMMU_DOMAIN_IDENTITY; - ++ + if ((iommu_identity_mapping & IDENTMAP_IPU) && IS_INTEL_IPU(pdev)) + return IOMMU_DOMAIN_IDENTITY; + - if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) - return IOMMU_DOMAIN_IDENTITY; ++ if ((iommu_identity_mapping & IDENTMAP_IPTS) && IS_IPTS(pdev)) ++ return IOMMU_DOMAIN_IDENTITY; } -@@ -2874,6 +2885,9 @@ static int __init init_dmars(void) + + return 0; +@@ -2855,6 +2873,12 @@ static int __init init_dmars(void) if (!dmar_map_gfx) iommu_identity_mapping |= IDENTMAP_GFX; + if (!dmar_map_ipu) + iommu_identity_mapping |= IDENTMAP_IPU; + - if (!dmar_map_ipts) - iommu_identity_mapping |= IDENTMAP_IPTS; ++ if (!dmar_map_ipts) ++ iommu_identity_mapping |= IDENTMAP_IPTS; ++ + check_tylersburg_isoch(); -@@ -4788,6 +4802,18 @@ static void quirk_iommu_igfx(struct pci_dev *dev) + ret = si_domain_init(hw_pass_through); +@@ -4771,6 +4795,30 @@ static void quirk_iommu_igfx(struct pci_dev *dev) dmar_map_gfx = 0; } @@ -7897,272 +5241,298 @@ index 0d4542b7365d..c96a9baea21c 100644 + dmar_map_ipu = 0; +} + - static void quirk_iommu_ipts(struct pci_dev *dev) - { - if (!IS_IPTS(dev)) -@@ -4799,6 +4825,7 @@ static void quirk_iommu_ipts(struct pci_dev *dev) - pci_info(dev, "Passthrough IOMMU for IPTS\n"); - dmar_map_ipts = 0; - } ++static void quirk_iommu_ipts(struct pci_dev *dev) ++{ ++ if (!IS_IPTS(dev)) ++ return; ++ ++ if (risky_device(dev)) ++ return; ++ ++ pci_info(dev, "Passthrough IOMMU for IPTS\n"); ++ dmar_map_ipts = 0; ++} + /* 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); -@@ -4834,6 +4861,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1632, quirk_iommu_igfx); +@@ -4806,6 +4854,12 @@ 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); +/* disable IPU dmar support */ +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_iommu_ipu); + - /* disable IPTS dmar support */ - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); - --- -2.41.0 - -From cb948321e6e2d4a959b6e7890366028c5b4b7938 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 - -The TPS68470 PMIC has an I2C passthrough mode through which I2C traffic -can be forwarded to a device connected to the PMIC as though it were -connected directly to the system bus. Enable this mode when the chip -is initialised. - -Signed-off-by: Daniel Scally <djrscally@gmail.com> -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c -index 5b8d1a9620a5..6a0ff035cf20 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) - return ret; - } - -+ /* Enable I2C daisy chain */ -+ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); -+ if (ret) { -+ dev_err(dev, "Failed to enable i2c daisy chain\n"); -+ return ret; -+ } ++/* disable IPTS dmar support */ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9D3E, quirk_iommu_ipts); + - dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - - return 0; --- -2.41.0 - -From c3df3ab4a47d2ebce9e23be3863709480c6f5247 Mon Sep 17 00:00:00 2001 -From: Daniel Scally <djrscally@gmail.com> -Date: Wed, 4 May 2022 23:21:45 +0100 -Subject: [PATCH] media: ipu3-cio2: Move functionality from .complete() to - .bound() - -Creating links and registering subdev nodes during the .complete() -callback has the unfortunate effect of preventing all cameras that -connect to a notifier from working if any one of their drivers fails -to probe. Moving the functionality from .complete() to .bound() allows -those camera sensor drivers that did probe correctly to work regardless. - -Signed-off-by: Daniel Scally <djrscally@gmail.com> -Patchset: cameras ---- - drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 65 +++++++------------ - 1 file changed, 23 insertions(+), 42 deletions(-) - -diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -index 3c84cb121632..8ba5f78baf9c 100644 ---- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -@@ -1384,7 +1384,10 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, + static void quirk_iommu_rwbf(struct pci_dev *dev) { - struct cio2_device *cio2 = to_cio2_device(notifier); - struct sensor_async_subdev *s_asd = to_sensor_asd(asd); -+ struct device *dev = &cio2->pci_dev->dev; - struct cio2_queue *q; -+ unsigned int pad; -+ int ret; + if (risky_device(dev)) +diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c +index 08f56326e..75218b389 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) + data.busmatch_count = 0; + pci_for_each_dma_alias(dev, set_msi_sid_cb, &data); - if (cio2->queue[s_asd->csi2.port].sensor) - return -EBUSY; -@@ -1395,7 +1398,26 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, - q->sensor = sd; - q->csi_rx_base = cio2->base + CIO2_REG_PIPE_BASE(q->csi2.port); ++ /* ++ * The Intel Touch Host Controller is at 00:10.6, but for some reason ++ * the MSI interrupts have request id 01:05.0. ++ * Disable id verification to work around this. ++ * FIXME Find proper fix or turn this into a quirk. ++ */ ++ if (dev->vendor == PCI_VENDOR_ID_INTEL && (dev->class >> 8) == PCI_CLASS_INPUT_PEN) { ++ switch(dev->device) { ++ case 0x98d0: case 0x98d1: // LKF ++ case 0xa0d0: case 0xa0d1: // TGL LP ++ case 0x43d0: case 0x43d1: // TGL H ++ set_irte_sid(irte, SVT_NO_VERIFY, SQ_ALL_16, 0); ++ return 0; ++ } ++ } ++ + /* + * 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 +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 6046dfeca..385c06e4f 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -864,6 +864,18 @@ config LEDS_TPS6105X + It is a single boost converter primarily for white LEDs and + audio amplifiers. -- return 0; -+ for (pad = 0; pad < q->sensor->entity.num_pads; pad++) -+ if (q->sensor->entity.pads[pad].flags & -+ MEDIA_PAD_FL_SOURCE) -+ break; ++config LEDS_TPS68470 ++ tristate "LED support for TI TPS68470" ++ depends on LEDS_CLASS ++ depends on INTEL_SKL_INT3472 ++ help ++ This driver supports TPS68470 PMIC with LED chip. ++ It provides two LED controllers, with the ability to drive 2 ++ indicator LEDs and 2 flash LEDs. + -+ if (pad == q->sensor->entity.num_pads) { -+ dev_err(dev, "failed to find src pad for %s\n", -+ q->sensor->name); -+ return -ENXIO; ++ To compile this driver as a module, choose M and it will be ++ called leds-tps68470 ++ + config LEDS_IP30 + tristate "LED support for SGI Octane machines" + depends on LEDS_CLASS +diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile +index d71f12265..e2002b535 100644 +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -83,6 +83,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o + obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o + obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o + obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o ++obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o + obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o + obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o + 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 000000000..35aeb5db8 +--- /dev/null ++++ b/drivers/leds/leds-tps68470.c +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * LED driver for TPS68470 PMIC ++ * ++ * Copyright (C) 2023 Red Hat ++ * ++ * Authors: ++ * Kate Hsuan <hpa@redhat.com> ++ */ ++ ++#include <linux/leds.h> ++#include <linux/mfd/tps68470.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/property.h> ++#include <linux/regmap.h> ++ ++ ++#define lcdev_to_led(led_cdev) \ ++ container_of(led_cdev, struct tps68470_led, lcdev) ++ ++#define led_to_tps68470(led, index) \ ++ container_of(led, struct tps68470_device, leds[index]) ++ ++enum tps68470_led_ids { ++ TPS68470_ILED_A, ++ TPS68470_ILED_B, ++ TPS68470_NUM_LEDS ++}; ++ ++static const char *tps68470_led_names[] = { ++ [TPS68470_ILED_A] = "tps68470-iled_a", ++ [TPS68470_ILED_B] = "tps68470-iled_b", ++}; ++ ++struct tps68470_led { ++ unsigned int led_id; ++ struct led_classdev lcdev; ++}; ++ ++struct tps68470_device { ++ struct device *dev; ++ struct regmap *regmap; ++ struct tps68470_led leds[TPS68470_NUM_LEDS]; ++}; ++ ++enum ctrlb_current { ++ CTRLB_2MA = 0, ++ CTRLB_4MA = 1, ++ CTRLB_8MA = 2, ++ CTRLB_16MA = 3, ++}; ++ ++static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, ++ brightness ? TPS68470_ILEDCTL_ENA : 0); ++ case TPS68470_ILED_B: ++ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, ++ brightness ? TPS68470_ILEDCTL_ENB : 0); + } ++ return -EINVAL; ++} + -+ ret = media_create_pad_link(&q->sensor->entity, pad, &q->subdev.entity, -+ CIO2_PAD_SINK, 0); -+ if (ret) { -+ dev_err(dev, "failed to create link for %s\n", -+ q->sensor->name); -+ return ret; ++static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++{ ++ struct tps68470_led *led = lcdev_to_led(led_cdev); ++ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); ++ struct regmap *regmap = tps68470->regmap; ++ int ret = 0; ++ int value = 0; ++ ++ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); ++ if (ret) ++ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ ++ switch (led->led_id) { ++ case TPS68470_ILED_A: ++ value = value & TPS68470_ILEDCTL_ENA; ++ break; ++ case TPS68470_ILED_B: ++ value = value & TPS68470_ILEDCTL_ENB; ++ break; + } + -+ return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); - } - - /* The .unbind callback */ -@@ -1409,50 +1431,9 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, - cio2->queue[s_asd->csi2.port].sensor = NULL; - } - --/* .complete() is called after all subdevices have been located */ --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_subdev *asd; -- struct cio2_queue *q; -- unsigned int pad; -- int ret; -- -- list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) { -- s_asd = to_sensor_asd(asd); -- q = &cio2->queue[s_asd->csi2.port]; -- -- for (pad = 0; pad < q->sensor->entity.num_pads; pad++) -- if (q->sensor->entity.pads[pad].flags & -- MEDIA_PAD_FL_SOURCE) -- break; -- -- if (pad == q->sensor->entity.num_pads) { -- dev_err(dev, "failed to find src pad for %s\n", -- q->sensor->name); -- return -ENXIO; -- } -- -- ret = media_create_pad_link( -- &q->sensor->entity, pad, -- &q->subdev.entity, CIO2_PAD_SINK, -- 0); -- if (ret) { -- dev_err(dev, "failed to create link for %s\n", -- q->sensor->name); -- return ret; -- } -- } -- -- return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); --} -- - static const struct v4l2_async_notifier_operations cio2_async_ops = { - .bound = cio2_notifier_bound, - .unbind = cio2_notifier_unbind, -- .complete = cio2_notifier_complete, - }; - - static int cio2_parse_firmware(struct cio2_device *cio2) --- -2.41.0 - -From b551835863227b32672a1d7047f335efe7c1c332 Mon Sep 17 00:00:00 2001 -From: Daniel Scally <djrscally@gmail.com> -Date: Thu, 2 Jun 2022 22:15:56 +0100 -Subject: [PATCH] media: ipu3-cio2: Re-add .complete() to ipu3-cio2 - -Removing the .complete() callback had some unintended consequences. -Because the VCM driver is not directly linked to the ipu3-cio2 -driver .bound() never gets called for it, which means its devnode -is never created if it probes late. Because .complete() waits for -any sub-notifiers to also be complete it is captured in that call. - -Signed-off-by: Daniel Scally <djrscally@gmail.com> -Patchset: cameras ---- - drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -index 8ba5f78baf9c..f0b77012641b 100644 ---- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c -@@ -1431,9 +1431,18 @@ static void cio2_notifier_unbind(struct v4l2_async_notifier *notifier, - cio2->queue[s_asd->csi2.port].sensor = NULL; - } - -+/* .complete() is called after all subdevices have been located */ -+static int cio2_notifier_complete(struct v4l2_async_notifier *notifier) ++ return value ? LED_ON : LED_OFF; ++} ++ ++ ++static int tps68470_ledb_current_init(struct platform_device *pdev, ++ struct tps68470_device *tps68470) +{ -+ struct cio2_device *cio2 = to_cio2_device(notifier); ++ int ret = 0; ++ unsigned int curr; + -+ return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); ++ /* configure LEDB current if the properties can be got */ ++ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { ++ if (curr > CTRLB_16MA) { ++ dev_err(&pdev->dev, ++ "Invalid LEDB current value: %d\n", ++ curr); ++ return -EINVAL; ++ } ++ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, ++ TPS68470_ILEDCTL_CTRLB, curr); ++ } ++ return ret; +} + - static const struct v4l2_async_notifier_operations cio2_async_ops = { - .bound = cio2_notifier_bound, - .unbind = cio2_notifier_unbind, -+ .complete = cio2_notifier_complete, - }; - - static int cio2_parse_firmware(struct cio2_device *cio2) --- -2.41.0 - -From 134f10f3f9d08098e3b2fed34d894b44bf8b9109 Mon Sep 17 00:00:00 2001 -From: Daniel Scally <djrscally@gmail.com> -Date: Thu, 28 Oct 2021 21:55:16 +0100 -Subject: [PATCH] media: i2c: Add driver for DW9719 VCM - -Add a driver for the DW9719 VCM. The driver creates a v4l2 subdevice -and registers a control to set the desired focus. - -Signed-off-by: Daniel Scally <djrscally@gmail.com> -Patchset: cameras ---- - MAINTAINERS | 7 + - drivers/media/i2c/Kconfig | 11 + - drivers/media/i2c/Makefile | 1 + - drivers/media/i2c/dw9719.c | 425 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 444 insertions(+) - create mode 100644 drivers/media/i2c/dw9719.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index 35e19594640d..7e6631f0b55b 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -6262,6 +6262,13 @@ T: git git://linuxtv.org/media_tree.git - F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml - F: drivers/media/i2c/dw9714.c - -+DONGWOON DW9719 LENS VOICE COIL DRIVER -+M: Daniel Scally <djrscally@gmail.com> -+L: linux-media@vger.kernel.org -+S: Maintained -+T: git git://linuxtv.org/media_tree.git -+F: drivers/media/i2c/dw9719.c ++static int tps68470_leds_probe(struct platform_device *pdev) ++{ ++ int i = 0; ++ int ret = 0; ++ struct tps68470_device *tps68470; ++ struct tps68470_led *led; ++ struct led_classdev *lcdev; + - DONGWOON DW9768 LENS VOICE COIL DRIVER - M: Dongchun Zhu <dongchun.zhu@mediatek.com> - L: linux-media@vger.kernel.org ++ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), ++ GFP_KERNEL); ++ if (!tps68470) ++ return -ENOMEM; ++ ++ tps68470->dev = &pdev->dev; ++ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ led = &tps68470->leds[i]; ++ lcdev = &led->lcdev; ++ ++ led->led_id = i; ++ ++ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", ++ tps68470_led_names[i], LED_FUNCTION_INDICATOR); ++ if (!lcdev->name) ++ return -ENOMEM; ++ ++ lcdev->max_brightness = 1; ++ lcdev->brightness = 0; ++ lcdev->brightness_set_blocking = tps68470_brightness_set; ++ lcdev->brightness_get = tps68470_brightness_get; ++ lcdev->dev = &pdev->dev; ++ ++ ret = devm_led_classdev_register(tps68470->dev, lcdev); ++ if (ret) { ++ dev_err_probe(tps68470->dev, ret, ++ "error registering led\n"); ++ goto err_exit; ++ } ++ ++ if (i == TPS68470_ILED_B) { ++ ret = tps68470_ledb_current_init(pdev, tps68470); ++ if (ret) ++ goto err_exit; ++ } ++ } ++ ++err_exit: ++ if (ret) { ++ for (i = 0; i < TPS68470_NUM_LEDS; i++) { ++ if (tps68470->leds[i].lcdev.name) ++ devm_led_classdev_unregister(&pdev->dev, ++ &tps68470->leds[i].lcdev); ++ } ++ } ++ ++ return ret; ++} ++static struct platform_driver tps68470_led_driver = { ++ .driver = { ++ .name = "tps68470-led", ++ }, ++ .probe = tps68470_leds_probe, ++}; ++ ++module_platform_driver(tps68470_led_driver); ++ ++MODULE_ALIAS("platform:tps68470-led"); ++MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index 256d55bb2b1d..c9587f500a88 100644 +index 226454b6a..ddddf6849 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig -@@ -835,6 +835,17 @@ config VIDEO_DW9714 +@@ -848,6 +848,17 @@ config VIDEO_DW9714 capability. This is designed for linear control of voice coil motors, controlled via I2C serial interface. +config VIDEO_DW9719 + tristate "DW9719 lens voice coil support" -+ depends on I2C && VIDEO_V4L2 ++ depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_ASYNC @@ -8175,7 +5545,7 @@ index 256d55bb2b1d..c9587f500a88 100644 tristate "DW9768 lens voice coil support" depends on I2C && VIDEO_DEV diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile -index b44dacf935f4..2a68bfb621b0 100644 +index c743aeb5d..db1ebf5ca 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_VIDEO_CS5345) += cs5345.o @@ -8188,7 +5558,7 @@ index b44dacf935f4..2a68bfb621b0 100644 obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c new file mode 100644 -index 000000000000..180b04d2a6b3 +index 000000000..180b04d2a --- /dev/null +++ b/drivers/media/i2c/dw9719.c @@ -0,0 +1,425 @@ @@ -8617,110 +5987,8 @@ index 000000000000..180b04d2a6b3 +MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>"); +MODULE_DESCRIPTION("DW9719 VCM Driver"); +MODULE_LICENSE("GPL"); --- -2.41.0 - -From 4d00c4ddfa59ab50aace2ffce596f49306d5f05e Mon Sep 17 00:00:00 2001 -From: Maximilian Luz <luzmaximilian@gmail.com> -Date: Fri, 15 Jul 2022 23:48:00 +0200 -Subject: [PATCH] drivers/media/i2c: Fix DW9719 dependencies - -It should depend on VIDEO_DEV instead of VIDEO_V4L2. - -Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com> -Patchset: cameras ---- - drivers/media/i2c/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig -index c9587f500a88..0e5a69d5d7ff 100644 ---- a/drivers/media/i2c/Kconfig -+++ b/drivers/media/i2c/Kconfig -@@ -837,7 +837,7 @@ config VIDEO_DW9714 - - config VIDEO_DW9719 - tristate "DW9719 lens voice coil support" -- depends on I2C && VIDEO_V4L2 -+ depends on I2C && VIDEO_DEV - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select V4L2_ASYNC --- -2.41.0 - -From cc9a03f16748473f0ef48cbf0dea5529023a357e 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 - -ACPI _HID INT347E represents the OmniVision 7251 camera sensor. The -driver for this sensor expects a single pin named "enable", but on -some Microsoft Surface platforms the sensor is assigned a single -GPIO who's type flag is INT3472_GPIO_TYPE_RESET. - -Remap the GPIO pin's function from "reset" to "enable". This is done -outside of the existing remap table since it is a more widespread -discrepancy than that method is designed for. Additionally swap the -polarity of the pin to match the driver's expectation. - -Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/discrete.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c -index ef020e23e596..d21ef437c2f6 100644 ---- a/drivers/platform/x86/intel/int3472/discrete.c -+++ b/drivers/platform/x86/intel/int3472/discrete.c -@@ -98,6 +98,9 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - { - const struct int3472_sensor_config *sensor_config; - char *path = agpio->resource_source.string_ptr; -+ const struct acpi_device_id ov7251_ids[] = { -+ { "INT347E" }, -+ }; - struct gpiod_lookup *table_entry; - struct acpi_device *adev; - acpi_handle handle; -@@ -120,6 +123,17 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 - } - } - -+ /* -+ * In addition to the function remap table we need to bulk remap the -+ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that -+ * expects its only GPIO pin to be called "enable" (and to have the -+ * opposite polarity). -+ */ -+ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { -+ func = "enable"; -+ polarity = GPIO_ACTIVE_HIGH; -+ } -+ - /* Functions mapped to NULL should not be mapped to the sensor */ - if (!func) - return 0; --- -2.41.0 - -From 44f08fa3e281a7019ef0a1b2db7c1319cc0da80e 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 - -Update the control ID for the gain control in the ov7251 driver to -V4L2_CID_ANALOGUE_GAIN. - -Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> -Patchset: cameras ---- - drivers/media/i2c/ov7251.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c -index 88e987435285..ff7b2c26da83 100644 +index 675fb37a6..43b30db08 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) @@ -8741,29 +6009,86 @@ index 88e987435285..ff7b2c26da83 100644 v4l2_ctrl_new_std_menu_items(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, --- -2.41.0 - -From d3a4b533b2932bdd6398ea430cfca8fa7d51386c 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 - v4l2_async_register_subdev() - -The current call to v4l2_subdev_get_privacy_led() is contained in -v4l2_async_register_subdev_sensor(), but that function isn't used by -all the sensor drivers. Move the acquisition of the privacy led to -v4l2_async_register_subdev() instead. - -Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com> -Patchset: cameras ---- - drivers/media/v4l2-core/v4l2-async.c | 4 ++++ - drivers/media/v4l2-core/v4l2-fwnode.c | 4 ---- - 2 files changed, 4 insertions(+), 4 deletions(-) - +diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +index 34984a747..67a44f6da 100644 +--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c ++++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +@@ -1385,7 +1385,10 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, + { + struct cio2_device *cio2 = to_cio2_device(notifier); + struct sensor_async_subdev *s_asd = to_sensor_asd(asd); ++ struct device *dev = &cio2->pci_dev->dev; + struct cio2_queue *q; ++ unsigned int pad; ++ int ret; + + if (cio2->queue[s_asd->csi2.port].sensor) + return -EBUSY; +@@ -1396,7 +1399,26 @@ static int cio2_notifier_bound(struct v4l2_async_notifier *notifier, + q->sensor = sd; + q->csi_rx_base = cio2->base + CIO2_REG_PIPE_BASE(q->csi2.port); + +- return 0; ++ for (pad = 0; pad < q->sensor->entity.num_pads; pad++) ++ if (q->sensor->entity.pads[pad].flags & ++ MEDIA_PAD_FL_SOURCE) ++ break; ++ ++ if (pad == q->sensor->entity.num_pads) { ++ dev_err(dev, "failed to find src pad for %s\n", ++ q->sensor->name); ++ return -ENXIO; ++ } ++ ++ ret = media_create_pad_link(&q->sensor->entity, pad, &q->subdev.entity, ++ CIO2_PAD_SINK, 0); ++ if (ret) { ++ dev_err(dev, "failed to create link for %s\n", ++ q->sensor->name); ++ return ret; ++ } ++ ++ return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); + } + + /* The .unbind callback */ +@@ -1414,34 +1436,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_subdev *asd; +- struct cio2_queue *q; +- int ret; +- +- list_for_each_entry(asd, &cio2->notifier.asd_list, asd_list) { +- 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); +- return ret; +- } +- } + + return v4l2_device_register_subdev_nodes(&cio2->v4l2_dev); + } diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c -index b16b5f4cb91e..33739a979cbc 100644 +index b16b5f4cb..33739a979 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -760,6 +760,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) @@ -8778,7 +6103,7 @@ index b16b5f4cb91e..33739a979cbc 100644 * No reference taken. The reference is held by the device * (struct v4l2_subdev.dev), and async sub-device does not diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 049c2f2001ea..f8c3e40b2b71 100644 +index 049c2f200..f8c3e40b2 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1304,10 +1304,6 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) @@ -8792,557 +6117,804 @@ index 049c2f2001ea..f8c3e40b2b71 100644 ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); if (ret < 0) goto out_cleanup; --- -2.41.0 - -From 33d5408f18336da004bf9f86d1add568b184624f 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 - -Add MFD cell for tps68470-led. - -Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> -Signed-off-by: Kate Hsuan <hpa@redhat.com> -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Patchset: cameras ---- - drivers/platform/x86/intel/int3472/tps68470.c | 5 +++-- - 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 6a0ff035cf20..2a7d01d3abc8 100644 ---- a/drivers/platform/x86/intel/int3472/tps68470.c -+++ b/drivers/platform/x86/intel/int3472/tps68470.c -@@ -17,7 +17,7 @@ - #define DESIGNED_FOR_CHROMEOS 1 - #define DESIGNED_FOR_WINDOWS 2 +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index bdc65d50b..08723c01d 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -92,6 +92,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ --#define TPS68470_WIN_MFD_CELL_COUNT 3 -+#define TPS68470_WIN_MFD_CELL_COUNT 4 + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_3 0x34E4 /* Ice Lake Point LP 3 (iTouch) */ + #define MEI_DEV_ID_ICP_N 0x38E0 /* Ice Lake Point N */ - static const struct mfd_cell tps68470_cros[] = { - { .name = "tps68470-gpio" }, -@@ -200,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) - cells[1].name = "tps68470-regulator"; - cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; - cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); -- cells[2].name = "tps68470-gpio"; -+ cells[2].name = "tps68470-led"; -+ cells[3].name = "tps68470-gpio"; + #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 676d566f3..6b37dd1f8 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[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)}, - for (i = 0; i < board_data->n_gpiod_lookups; i++) - gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); --- -2.41.0 - -From 414acb5a6b1bb43e1bc2df05a77b4f4cd0e46925 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 - -Add flags for both LEDA(TPS68470_ILEDCTL_ENA), LEDB -(TPS68470_ILEDCTL_ENB), and current control mask for LEDB -(TPS68470_ILEDCTL_CTRLB) - -Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com> -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Signed-off-by: Kate Hsuan <hpa@redhat.com> -Patchset: cameras ---- - include/linux/mfd/tps68470.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h -index 7807fa329db0..2d2abb25b944 100644 ---- a/include/linux/mfd/tps68470.h -+++ b/include/linux/mfd/tps68470.h -@@ -34,6 +34,7 @@ - #define TPS68470_REG_SGPO 0x22 - #define TPS68470_REG_GPDI 0x26 - #define TPS68470_REG_GPDO 0x27 -+#define TPS68470_REG_ILEDCTL 0x28 - #define TPS68470_REG_VCMVAL 0x3C - #define TPS68470_REG_VAUX1VAL 0x3D - #define TPS68470_REG_VAUX2VAL 0x3E -@@ -94,4 +95,8 @@ - #define TPS68470_GPIO_MODE_OUT_CMOS 2 - #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_3, MEI_ME_PCH12_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)}, -+#define TPS68470_ILEDCTL_ENA BIT(2) -+#define TPS68470_ILEDCTL_ENB BIT(6) -+#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)}, +diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c +index 6cdb225b7..19c036751 100644 +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -38,6 +38,9 @@ static bool fw_diag_log; + /* frame mode values are mapped as per enum ath10k_hw_txrx_mode */ + unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI; + ++static char *override_board = ""; ++static char *override_board2 = ""; + - #endif /* __LINUX_MFD_TPS68470_H */ --- -2.41.0 - -From 405426bd01c4cb3646afb639b945f79844e525fe 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 - -There are two LED controllers, LEDA indicator LED and LEDB flash LED for -tps68470. LEDA can be enabled by setting TPS68470_ILEDCTL_ENA. Moreover, -tps68470 provides four levels of power status for LEDB. If the -properties called "ti,ledb-current" can be found, the current will be -set according to the property values. These two LEDs can be controlled -through the LED class of sysfs (tps68470-leda and tps68470-ledb). - -Signed-off-by: Kate Hsuan <hpa@redhat.com> -Reviewed-by: Hans de Goede <hdegoede@redhat.com> -Patchset: cameras ---- - drivers/leds/Kconfig | 12 +++ - drivers/leds/Makefile | 1 + - drivers/leds/leds-tps68470.c | 185 +++++++++++++++++++++++++++++++++++ - 3 files changed, 198 insertions(+) - create mode 100644 drivers/leds/leds-tps68470.c - -diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig -index 2c5fdf848210..ead139f0df52 100644 ---- a/drivers/leds/Kconfig -+++ b/drivers/leds/Kconfig -@@ -841,6 +841,18 @@ config LEDS_TPS6105X - It is a single boost converter primarily for white LEDs and - audio amplifiers. + unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | + BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); -+config LEDS_TPS68470 -+ tristate "LED support for TI TPS68470" -+ depends on LEDS_CLASS -+ depends on INTEL_SKL_INT3472 +@@ -50,6 +53,9 @@ module_param(fw_diag_log, bool, 0644); + module_param_named(frame_mode, ath10k_frame_mode, uint, 0644); + module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); + ++module_param(override_board, charp, 0644); ++module_param(override_board2, charp, 0644); ++ + MODULE_PARM_DESC(debug_mask, "Debugging mask"); + MODULE_PARM_DESC(uart_print, "Uart target debugging"); + MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); +@@ -59,6 +65,9 @@ MODULE_PARM_DESC(frame_mode, + MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); + MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); + ++MODULE_PARM_DESC(override_board, "Override for board.bin file"); ++MODULE_PARM_DESC(override_board2, "Override for board-2.bin file"); ++ + static const struct ath10k_hw_params ath10k_hw_params_list[] = { + { + .id = QCA988X_HW_2_0_VERSION, +@@ -911,6 +920,42 @@ static int ath10k_init_configure_target(struct ath10k *ar) + return 0; + } + ++static const char *ath10k_override_board_fw_file(struct ath10k *ar, ++ const char *file) ++{ ++ if (strcmp(file, "board.bin") == 0) { ++ if (strcmp(override_board, "") == 0) ++ return file; ++ ++ if (strcmp(override_board, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board.bin' with '%s'\n", ++ override_board); ++ ++ return override_board; ++ } ++ ++ if (strcmp(file, "board-2.bin") == 0) { ++ if (strcmp(override_board2, "") == 0) ++ return file; ++ ++ if (strcmp(override_board2, "none") == 0) { ++ dev_info(ar->dev, "firmware override: pretending 'board-2.bin' does not exist\n"); ++ return NULL; ++ } ++ ++ dev_info(ar->dev, "firmware override: replacing 'board-2.bin' with '%s'\n", ++ override_board2); ++ ++ return override_board2; ++ } ++ ++ return file; ++} ++ + static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) +@@ -925,6 +970,19 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + if (dir == NULL) + dir = "."; + ++ /* HACK: Override board.bin and board-2.bin files if specified. ++ * ++ * Some Surface devices perform better with a different board ++ * configuration. To this end, one would need to replace the board.bin ++ * file with the modified config and remove the board-2.bin file. ++ * Unfortunately, that's not a solution that we can easily package. So ++ * we add module options to perform these overrides here. ++ */ ++ ++ file = ath10k_override_board_fw_file(ar, file); ++ if (!file) ++ return ERR_PTR(-ENOENT); ++ + snprintf(filename, sizeof(filename), "%s/%s", dir, file); + ret = firmware_request_nowarn(&fw, filename, ar->dev); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 9a698a16a..5e1a341f6 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -368,6 +368,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -409,6 +410,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +@@ -1762,9 +1769,21 @@ mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) + static int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; ++ struct pci_dev *pdev = card->dev; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + const struct mwifiex_pcie_card_reg *reg = card->pcie.reg; + int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask; + ++ /* Trigger a function level reset of the PCI bridge device, this makes ++ * the firmware of PCIe 88W8897 cards stop reporting a fixed LTR value ++ * that prevents the system from entering package C10 and S0ix powersaving ++ * states. ++ * We need to do it here because it must happen after firmware ++ * initialization and this function is called after that is done. ++ */ ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ pci_reset_function(parent_pdev); ++ + /* Write the RX ring read pointer in to reg->rx_rdptr */ + if (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 dd6d21f1d..99b024ecb 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -13,7 +13,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -22,7 +24,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -31,7 +35,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -39,7 +45,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -47,7 +55,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -55,7 +65,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -63,7 +75,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -71,7 +85,9 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_DO_FLR_ON_BRIDGE | ++ QUIRK_NO_BRIDGE_D3), + }, + {} + }; +@@ -89,6 +105,11 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_DO_FLR_ON_BRIDGE) ++ dev_info(&pdev->dev, "quirk do_flr_on_bridge enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + 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 d6ff964ae..c14eb56eb 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -4,6 +4,8 @@ + #include "pcie.h" + + #define QUIRK_FW_RST_D3COLD BIT(0) ++#define QUIRK_DO_FLR_ON_BRIDGE BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c +index 55648c5fe..f1402fc70 100644 +--- a/drivers/pci/pci-driver.c ++++ b/drivers/pci/pci-driver.c +@@ -514,6 +514,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; + ++ if (pci_dev->no_shutdown) ++ return; ++ + pm_runtime_resume(dev); + + if (drv && drv->shutdown) +diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c +index fc399e56e..f0dbe43d6 100644 +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -6162,3 +6162,39 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2d, dpc_log_size); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a2f, dpc_log_size); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9a31, dpc_log_size); + #endif ++ ++static const struct dmi_system_id no_shutdown_dmi_table[] = { ++ /* ++ * Systems on which some devices should not be touched during shutdown. ++ */ ++ { ++ .ident = "Microsoft Surface Pro 9", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Pro 9"), ++ }, ++ }, ++ { ++ .ident = "Microsoft Surface Laptop 5", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 5"), ++ }, ++ }, ++ {} ++}; ++ ++static void quirk_no_shutdown(struct pci_dev *dev) ++{ ++ if (!dmi_check_system(no_shutdown_dmi_table)) ++ return; ++ ++ dev->no_shutdown = 1; ++ pci_info(dev, "disabling shutdown ops for [%04x:%04x]\n", ++ dev->vendor, dev->device); ++} ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461e, quirk_no_shutdown); // Thunderbolt 4 USB Controller ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x461f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x462f, quirk_no_shutdown); // Thunderbolt 4 PCI Express Root Port ++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/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig +index b629e82af..68656e8f3 100644 +--- a/drivers/platform/surface/Kconfig ++++ b/drivers/platform/surface/Kconfig +@@ -149,6 +149,13 @@ config SURFACE_AGGREGATOR_TABLET_SWITCH + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + ++config SURFACE_BOOK1_DGPU_SWITCH ++ tristate "Surface Book 1 dGPU Switch Driver" ++ depends on SYSFS + help -+ This driver supports TPS68470 PMIC with LED chip. -+ It provides two LED controllers, with the ability to drive 2 -+ indicator LEDs and 2 flash LEDs. ++ This driver provides a sysfs switch to set the power-state of the ++ discrete GPU found on the Microsoft Surface Book 1. + -+ To compile this driver as a module, choose M and it will be -+ called leds-tps68470 + config SURFACE_DTX + tristate "Surface DTX (Detachment System) Driver" + depends on SURFACE_AGGREGATOR +diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile +index 533443309..7efcd0cdb 100644 +--- a/drivers/platform/surface/Makefile ++++ b/drivers/platform/surface/Makefile +@@ -12,6 +12,7 @@ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o + obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o + obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o + obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o ++obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += surfacebook1_dgpu_switch.o + obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o + obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o +diff --git a/drivers/platform/surface/surface3-wmi.c b/drivers/platform/surface/surface3-wmi.c +index ca4602bcc..490b97310 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[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + #endif + { } + }; +diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c +index c219b840d..69c4352e8 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[] = { + {}, + }; + ++static const struct property_entry lid_device_props_l52[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x52), ++ {}, ++}; + - config LEDS_IP30 - tristate "LED support for SGI Octane machines" - depends on LEDS_CLASS -diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile -index c07d1512c745..dd78cb6ef22e 100644 ---- a/drivers/leds/Makefile -+++ b/drivers/leds/Makefile -@@ -81,6 +81,7 @@ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o - obj-$(CONFIG_LEDS_TI_LMU_COMMON) += leds-ti-lmu-common.o - obj-$(CONFIG_LEDS_TLC591XX) += leds-tlc591xx.o - obj-$(CONFIG_LEDS_TPS6105X) += leds-tps6105x.o -+obj-$(CONFIG_LEDS_TPS68470) += leds-tps68470.o - obj-$(CONFIG_LEDS_TURRIS_OMNIA) += leds-turris-omnia.o - obj-$(CONFIG_LEDS_WM831X_STATUS) += leds-wm831x-status.o - obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o -diff --git a/drivers/leds/leds-tps68470.c b/drivers/leds/leds-tps68470.c + static const struct property_entry lid_device_props_l57[] = { + PROPERTY_ENTRY_U32("gpe", 0x57), + {}, +@@ -107,6 +112,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { + }, + .driver_data = (void *)lid_device_props_l4B, + }, ++ { ++ /* ++ * We match for SKU here due to product name clash with the ARM ++ * version. ++ */ ++ .ident = "Surface Pro 9", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_9_2038"), ++ }, ++ .driver_data = (void *)lid_device_props_l52, ++ }, + { + .ident = "Surface Book 1", + .matches = { +diff --git a/drivers/platform/surface/surfacebook1_dgpu_switch.c b/drivers/platform/surface/surfacebook1_dgpu_switch.c new file mode 100644 -index 000000000000..35aeb5db89c8 +index 000000000..8b816ed8f --- /dev/null -+++ b/drivers/leds/leds-tps68470.c -@@ -0,0 +1,185 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * LED driver for TPS68470 PMIC -+ * -+ * Copyright (C) 2023 Red Hat -+ * -+ * Authors: -+ * Kate Hsuan <hpa@redhat.com> -+ */ ++++ b/drivers/platform/surface/surfacebook1_dgpu_switch.c +@@ -0,0 +1,162 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + -+#include <linux/leds.h> -+#include <linux/mfd/tps68470.h> ++#include <linux/kernel.h> +#include <linux/module.h> ++#include <linux/acpi.h> +#include <linux/platform_device.h> -+#include <linux/property.h> -+#include <linux/regmap.h> + + -+#define lcdev_to_led(led_cdev) \ -+ container_of(led_cdev, struct tps68470_led, lcdev) ++#ifdef pr_fmt ++#undef pr_fmt ++#endif ++#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ + -+#define led_to_tps68470(led, index) \ -+ container_of(led, struct tps68470_device, leds[index]) + -+enum tps68470_led_ids { -+ TPS68470_ILED_A, -+ TPS68470_ILED_B, -+ TPS68470_NUM_LEDS -+}; ++static const guid_t dgpu_sw_guid = GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, ++ 0x95, 0xed, 0xab, 0x16, 0x65, 0x49, 0x80, 0x35); + -+static const char *tps68470_led_names[] = { -+ [TPS68470_ILED_A] = "tps68470-iled_a", -+ [TPS68470_ILED_B] = "tps68470-iled_b", -+}; ++#define DGPUSW_ACPI_PATH_DSM "\\_SB_.PCI0.LPCB.EC0_.VGBI" ++#define DGPUSW_ACPI_PATH_HGON "\\_SB_.PCI0.RP05.HGON" ++#define DGPUSW_ACPI_PATH_HGOF "\\_SB_.PCI0.RP05.HGOF" + -+struct tps68470_led { -+ unsigned int led_id; -+ struct led_classdev lcdev; -+}; + -+struct tps68470_device { -+ struct device *dev; -+ struct regmap *regmap; -+ struct tps68470_led leds[TPS68470_NUM_LEDS]; -+}; ++static int sb1_dgpu_sw_dsmcall(void) ++{ ++ union acpi_object *ret; ++ acpi_handle handle; ++ acpi_status status; + -+enum ctrlb_current { -+ CTRLB_2MA = 0, -+ CTRLB_4MA = 1, -+ CTRLB_8MA = 2, -+ CTRLB_16MA = 3, -+}; ++ status = acpi_get_handle(NULL, DGPUSW_ACPI_PATH_DSM, &handle); ++ if (status) ++ return -EINVAL; + -+static int tps68470_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) ++ ret = acpi_evaluate_dsm_typed(handle, &dgpu_sw_guid, 1, 1, NULL, ACPI_TYPE_BUFFER); ++ if (!ret) ++ return -EINVAL; ++ ++ ACPI_FREE(ret); ++ return 0; ++} ++ ++static int sb1_dgpu_sw_hgon(void) +{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; + -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENA, -+ brightness ? TPS68470_ILEDCTL_ENA : 0); -+ case TPS68470_ILED_B: -+ return regmap_update_bits(regmap, TPS68470_REG_ILEDCTL, TPS68470_ILEDCTL_ENB, -+ brightness ? TPS68470_ILEDCTL_ENB : 0); ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGON, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGON: %d\n", status); ++ return -EINVAL; + } -+ return -EINVAL; ++ ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-on dGPU via HGON\n"); ++ return 0; +} + -+static enum led_brightness tps68470_brightness_get(struct led_classdev *led_cdev) ++static int sb1_dgpu_sw_hgof(void) +{ -+ struct tps68470_led *led = lcdev_to_led(led_cdev); -+ struct tps68470_device *tps68470 = led_to_tps68470(led, led->led_id); -+ struct regmap *regmap = tps68470->regmap; -+ int ret = 0; -+ int value = 0; -+ -+ ret = regmap_read(regmap, TPS68470_REG_ILEDCTL, &value); -+ if (ret) -+ return dev_err_probe(led_cdev->dev, -EINVAL, "failed on reading register\n"); ++ struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; ++ acpi_status status; + -+ switch (led->led_id) { -+ case TPS68470_ILED_A: -+ value = value & TPS68470_ILEDCTL_ENA; -+ break; -+ case TPS68470_ILED_B: -+ value = value & TPS68470_ILEDCTL_ENB; -+ break; ++ status = acpi_evaluate_object(NULL, DGPUSW_ACPI_PATH_HGOF, NULL, &buf); ++ if (status) { ++ pr_err("failed to run HGOF: %d\n", status); ++ return -EINVAL; + } + -+ return value ? LED_ON : LED_OFF; ++ if (buf.pointer) ++ ACPI_FREE(buf.pointer); ++ ++ pr_info("turned-off dGPU via HGOF\n"); ++ return 0; +} + + -+static int tps68470_ledb_current_init(struct platform_device *pdev, -+ struct tps68470_device *tps68470) ++static ssize_t dgpu_dsmcall_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) +{ -+ int ret = 0; -+ unsigned int curr; ++ int status, value; + -+ /* configure LEDB current if the properties can be got */ -+ if (!device_property_read_u32(&pdev->dev, "ti,ledb-current", &curr)) { -+ if (curr > CTRLB_16MA) { -+ dev_err(&pdev->dev, -+ "Invalid LEDB current value: %d\n", -+ curr); -+ return -EINVAL; -+ } -+ ret = regmap_update_bits(tps68470->regmap, TPS68470_REG_ILEDCTL, -+ TPS68470_ILEDCTL_CTRLB, curr); -+ } -+ return ret; ++ status = kstrtoint(buf, 0, &value); ++ if (status < 0) ++ return status; ++ ++ if (value != 1) ++ return -EINVAL; ++ ++ status = sb1_dgpu_sw_dsmcall(); ++ ++ return status < 0 ? status : len; +} + -+static int tps68470_leds_probe(struct platform_device *pdev) ++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t len) +{ -+ int i = 0; -+ int ret = 0; -+ struct tps68470_device *tps68470; -+ struct tps68470_led *led; -+ struct led_classdev *lcdev; -+ -+ tps68470 = devm_kzalloc(&pdev->dev, sizeof(struct tps68470_device), -+ GFP_KERNEL); -+ if (!tps68470) -+ return -ENOMEM; ++ bool power; ++ int status; + -+ tps68470->dev = &pdev->dev; -+ tps68470->regmap = dev_get_drvdata(pdev->dev.parent); ++ status = kstrtobool(buf, &power); ++ if (status < 0) ++ return status; + -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ led = &tps68470->leds[i]; -+ lcdev = &led->lcdev; ++ if (power) ++ status = sb1_dgpu_sw_hgon(); ++ else ++ status = sb1_dgpu_sw_hgof(); + -+ led->led_id = i; ++ return status < 0 ? status : len; ++} + -+ lcdev->name = devm_kasprintf(tps68470->dev, GFP_KERNEL, "%s::%s", -+ tps68470_led_names[i], LED_FUNCTION_INDICATOR); -+ if (!lcdev->name) -+ return -ENOMEM; ++static DEVICE_ATTR_WO(dgpu_dsmcall); ++static DEVICE_ATTR_WO(dgpu_power); + -+ lcdev->max_brightness = 1; -+ lcdev->brightness = 0; -+ lcdev->brightness_set_blocking = tps68470_brightness_set; -+ lcdev->brightness_get = tps68470_brightness_get; -+ lcdev->dev = &pdev->dev; ++static struct attribute *sb1_dgpu_sw_attrs[] = { ++ &dev_attr_dgpu_dsmcall.attr, ++ &dev_attr_dgpu_power.attr, ++ NULL, ++}; + -+ ret = devm_led_classdev_register(tps68470->dev, lcdev); -+ if (ret) { -+ dev_err_probe(tps68470->dev, ret, -+ "error registering led\n"); -+ goto err_exit; -+ } ++static const struct attribute_group sb1_dgpu_sw_attr_group = { ++ .attrs = sb1_dgpu_sw_attrs, ++}; + -+ if (i == TPS68470_ILED_B) { -+ ret = tps68470_ledb_current_init(pdev, tps68470); -+ if (ret) -+ goto err_exit; -+ } -+ } + -+err_exit: -+ if (ret) { -+ for (i = 0; i < TPS68470_NUM_LEDS; i++) { -+ if (tps68470->leds[i].lcdev.name) -+ devm_led_classdev_unregister(&pdev->dev, -+ &tps68470->leds[i].lcdev); -+ } -+ } ++static int sb1_dgpu_sw_probe(struct platform_device *pdev) ++{ ++ return sysfs_create_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++} + -+ return ret; ++static int sb1_dgpu_sw_remove(struct platform_device *pdev) ++{ ++ sysfs_remove_group(&pdev->dev.kobj, &sb1_dgpu_sw_attr_group); ++ return 0; +} -+static struct platform_driver tps68470_led_driver = { ++ ++/* ++ * The dGPU power seems to be actually handled by MSHW0040. However, that is ++ * also the power-/volume-button device with a mainline driver. So let's use ++ * MSHW0041 instead for now, which seems to be the LTCH (latch/DTX) device. ++ */ ++static const struct acpi_device_id sb1_dgpu_sw_match[] = { ++ { "MSHW0041", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(acpi, sb1_dgpu_sw_match); ++ ++static struct platform_driver sb1_dgpu_sw = { ++ .probe = sb1_dgpu_sw_probe, ++ .remove = sb1_dgpu_sw_remove, + .driver = { -+ .name = "tps68470-led", ++ .name = "surfacebook1_dgpu_switch", ++ .acpi_match_table = sb1_dgpu_sw_match, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, -+ .probe = tps68470_leds_probe, +}; ++module_platform_driver(sb1_dgpu_sw); + -+module_platform_driver(tps68470_led_driver); -+ -+MODULE_ALIAS("platform:tps68470-led"); -+MODULE_DESCRIPTION("LED driver for TPS68470 PMIC"); -+MODULE_LICENSE("GPL v2"); --- -2.41.0 - -From 985951f1bb8716be7378d83fb285fe23cf86e31f 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 - override - -This patch is the work of Thomas Gleixner <tglx@linutronix.de> and is -copied from: -https://lore.kernel.org/lkml/87lf8ddjqx.ffs@nanos.tec.linutronix.de/ - -This patch adds a quirk to the ACPI setup to patch in the the irq 7 pin -setup that is missing in the laptops ACPI table. - -This patch was used for validation of the issue, and is not a proper -fix, but is probably a better temporary hack than continuing to probe -the Legacy PIC and run with the PIC in an unknown state. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index 21b542a6866c..fdd602e640b5 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -22,6 +22,7 @@ - #include <linux/efi-bgrt.h> - #include <linux/serial_core.h> - #include <linux/pgtable.h> -+#include <linux/dmi.h> ++MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); ++MODULE_DESCRIPTION("Discrete GPU Power-Switch for Surface Book 1"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/platform/surface/surfacepro3_button.c b/drivers/platform/surface/surfacepro3_button.c +index 2755601f9..4240c98ca 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) + /* + * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device + * ID (MSHW0040) for the power/volume buttons. Make sure this is the right +- * device by checking for the _DSM method and OEM Platform Revision. ++ * device by checking for the _DSM method and OEM Platform Revision DSM ++ * function. + * + * Returns true if the driver should bind to this device, i.e. the device is + * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. +@@ -157,30 +158,11 @@ static int surface_button_resume(struct device *dev) + static bool surface_button_check_MSHW0040(struct acpi_device *dev) + { + acpi_handle handle = dev->handle; +- union acpi_object *result; +- u64 oem_platform_rev = 0; // valid revisions are nonzero +- +- // get OEM platform revision +- result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, +- MSHW0040_DSM_REVISION, +- MSHW0040_DSM_GET_OMPR, +- NULL, ACPI_TYPE_INTEGER); +- +- /* +- * If evaluating the _DSM fails, the method is not present. This means +- * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we +- * should use this driver. We use revision 0 indicating it is +- * unavailable. +- */ +- +- if (result) { +- oem_platform_rev = result->integer.value; +- ACPI_FREE(result); +- } +- +- dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); - #include <asm/e820/api.h> - #include <asm/irqdomain.h> -@@ -1252,6 +1253,17 @@ static void __init mp_config_acpi_legacy_irqs(void) - } +- return oem_platform_rev == 0; ++ // make sure that OEM platform revision DSM call does not exist ++ return !acpi_check_dsm(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ BIT(MSHW0040_DSM_GET_OMPR)); } -+static const struct dmi_system_id surface_quirk[] __initconst = { -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") -+ }, -+ }, -+ {} -+}; -+ - /* - * Parse IOAPIC related entries in MADT - * returns 0 on success, < 0 on error -@@ -1307,6 +1319,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); -+ if (dmi_check_system(surface_quirk)) { -+ pr_warn("Surface hack: Override irq 7\n"); -+ mp_override_legacy_irq(7, 3, 3, 7); +diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c +index e33c2d759..c0c90ae66 100644 +--- a/drivers/platform/x86/intel/int3472/discrete.c ++++ b/drivers/platform/x86/intel/int3472/discrete.c +@@ -57,6 +57,9 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + const char *func, u32 polarity) + { + char *path = agpio->resource_source.string_ptr; ++ const struct acpi_device_id ov7251_ids[] = { ++ { "INT347E" }, ++ }; + struct gpiod_lookup *table_entry; + struct acpi_device *adev; + acpi_handle handle; +@@ -67,6 +70,17 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 + return -EINVAL; + } + ++ /* ++ * In addition to the function remap table we need to bulk remap the ++ * "reset" GPIO for the OmniVision 7251 sensor, as the driver for that ++ * expects its only GPIO pin to be called "enable" (and to have the ++ * opposite polarity). ++ */ ++ if (!strcmp(func, "reset") && !acpi_match_device_ids(int3472->sensor, ov7251_ids)) { ++ func = "enable"; ++ polarity = GPIO_ACTIVE_HIGH; + } + - /* Fill in identity legacy mappings where no override */ - mp_config_acpi_legacy_irqs(); - --- -2.41.0 - -From 8764552bf765a9dfea3d95093e5fdacc6dff3582 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 - quirk - -The 13" version of the Surface Laptop 4 has the same problem as the 15" -version, but uses a different SKU. Add that SKU to the quirk as well. - -Patchset: amd-gpio ---- - arch/x86/kernel/acpi/boot.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c -index fdd602e640b5..4e94eed20088 100644 ---- a/arch/x86/kernel/acpi/boot.c -+++ b/arch/x86/kernel/acpi/boot.c -@@ -1255,12 +1255,19 @@ static void __init mp_config_acpi_legacy_irqs(void) - - static const struct dmi_system_id surface_quirk[] __initconst = { - { -- .ident = "Microsoft Surface Laptop 4 (AMD)", -+ .ident = "Microsoft Surface Laptop 4 (AMD 15\")", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1952:1953") - }, - }, -+ { -+ .ident = "Microsoft Surface Laptop 4 (AMD 13\")", -+ .matches = { -+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), -+ DMI_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1958:1959") -+ }, -+ }, - {} - }; + status = acpi_get_handle(NULL, path, &handle); + if (ACPI_FAILURE(status)) + return -EINVAL; +diff --git a/drivers/platform/x86/intel/int3472/tps68470.c b/drivers/platform/x86/intel/int3472/tps68470.c +index 1e107fd49..423dc5550 100644 +--- a/drivers/platform/x86/intel/int3472/tps68470.c ++++ b/drivers/platform/x86/intel/int3472/tps68470.c +@@ -17,7 +17,7 @@ + #define DESIGNED_FOR_CHROMEOS 1 + #define DESIGNED_FOR_WINDOWS 2 --- -2.41.0 - -From 79625d878f8615b4e86131c9d539727b6e694894 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 - -The specification [1] allows so-called HW-reduced platforms, -which do not implement everything, especially the wakeup related stuff. - -In that case, it is still usable as a RTC. This is helpful for [2] -and [3], which is about a device with no other working RTC, -but it does have an HW-reduced TAD, which can be used as a RTC instead. - -[1]: https://uefi.org/specs/ACPI/6.5/09_ACPI_Defined_Devices_and_Device_Specific_Objects.html#time-and-alarm-device -[2]: https://bugzilla.kernel.org/show_bug.cgi?id=212313 -[3]: https://github.com/linux-surface/linux-surface/issues/415 - -Signed-off-by: Bart Groeneveld | GPX Solutions B.V. <bart@gpxbv.nl> -Patchset: rtc ---- - drivers/acpi/acpi_tad.c | 35 ++++++++++++++++++++++++----------- - 1 file changed, 24 insertions(+), 11 deletions(-) - -diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c -index e9b8e8305e23..944276934e7e 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, +-#define TPS68470_WIN_MFD_CELL_COUNT 3 ++#define TPS68470_WIN_MFD_CELL_COUNT 4 - static DEVICE_ATTR_RO(caps); + static const struct mfd_cell tps68470_cros[] = { + { .name = "tps68470-gpio" }, +@@ -46,6 +46,13 @@ static int tps68470_chip_init(struct device *dev, struct regmap *regmap) + return ret; + } -+static struct attribute *acpi_tad_attrs[] = { -+ &dev_attr_caps.attr, -+ NULL, -+}; -+static const struct attribute_group acpi_tad_attr_group = { -+ .attrs = acpi_tad_attrs, -+}; ++ /* Enable I2C daisy chain */ ++ ret = regmap_write(regmap, TPS68470_REG_S_I2C_CTL, 0x03); ++ if (ret) { ++ dev_err(dev, "Failed to enable i2c daisy chain\n"); ++ return ret; ++ } + - static ssize_t ac_alarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) - { -@@ -480,15 +488,14 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, - - static DEVICE_ATTR_RW(ac_status); - --static struct attribute *acpi_tad_attrs[] = { -- &dev_attr_caps.attr, -+static struct attribute *acpi_tad_ac_attrs[] = { - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, - }; --static const struct attribute_group acpi_tad_attr_group = { -- .attrs = acpi_tad_attrs, -+static const struct attribute_group acpi_tad_ac_attr_group = { -+ .attrs = acpi_tad_ac_attrs, - }; + dev_info(dev, "TPS68470 REVID: 0x%02x\n", version); - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, -@@ -563,13 +570,18 @@ static int acpi_tad_remove(struct platform_device *pdev) + return 0; +@@ -193,7 +200,8 @@ static int skl_int3472_tps68470_probe(struct i2c_client *client) + cells[1].name = "tps68470-regulator"; + cells[1].platform_data = (void *)board_data->tps68470_regulator_pdata; + cells[1].pdata_size = sizeof(struct tps68470_regulator_platform_data); +- cells[2].name = "tps68470-gpio"; ++ cells[2].name = "tps68470-led"; ++ cells[3].name = "tps68470-gpio"; - pm_runtime_get_sync(dev); + for (i = 0; i < board_data->n_gpiod_lookups; i++) + gpiod_add_lookup_table(board_data->tps68470_gpio_lookup_tables[i]); +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 15e9bd180..0d70461d0 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -220,6 +220,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 }, -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) -+ sysfs_remove_group(&dev->kobj, &acpi_tad_ac_attr_group); ++ /* Microsoft Surface Go 3 Type-Cover */ ++ { USB_DEVICE(0x045e, 0x09b5), .driver_info = USB_QUIRK_DELAY_INIT }, + - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); + /* Cherry Stream G230 2.0 (G85-231) and 3.0 (G85-232) */ + { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); +diff --git a/include/linux/mfd/tps68470.h b/include/linux/mfd/tps68470.h +index 7807fa329..2d2abb25b 100644 +--- a/include/linux/mfd/tps68470.h ++++ b/include/linux/mfd/tps68470.h +@@ -34,6 +34,7 @@ + #define TPS68470_REG_SGPO 0x22 + #define TPS68470_REG_GPDI 0x26 + #define TPS68470_REG_GPDO 0x27 ++#define TPS68470_REG_ILEDCTL 0x28 + #define TPS68470_REG_VCMVAL 0x3C + #define TPS68470_REG_VAUX1VAL 0x3D + #define TPS68470_REG_VAUX2VAL 0x3E +@@ -94,4 +95,8 @@ + #define TPS68470_GPIO_MODE_OUT_CMOS 2 + #define TPS68470_GPIO_MODE_OUT_ODRAIN 3 -- acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -- acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ if (dd->capabilities & ACPI_TAD_AC_WAKE) { -+ acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); -+ acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); -+ } - 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); -@@ -604,11 +616,6 @@ static int acpi_tad_probe(struct platform_device *pdev) - return -ENODEV; - } ++#define TPS68470_ILEDCTL_ENA BIT(2) ++#define TPS68470_ILEDCTL_ENB BIT(6) ++#define TPS68470_ILEDCTL_CTRLB GENMASK(5, 4) ++ + #endif /* __LINUX_MFD_TPS68470_H */ +diff --git a/include/linux/pci.h b/include/linux/pci.h +index b9ae5eb4c..c615fff3c 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -464,6 +464,7 @@ struct pci_dev { + unsigned int no_vf_scan:1; /* Don't scan for VFs after IOV enablement */ + unsigned int no_command_memory:1; /* No PCI_COMMAND_MEMORY */ + unsigned int rom_bar_overlap:1; /* ROM BAR disable broken */ ++ unsigned int no_shutdown:1; /* Do not touch device on shutdown */ + pci_dev_flags_t dev_flags; + atomic_t enable_cnt; /* pci_enable_device has been called */ -- if (!acpi_has_method(handle, "_PRW")) { -- dev_info(dev, "Missing _PRW\n"); -- return -ENODEV; -- } -- - dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; -@@ -637,6 +644,12 @@ static int acpi_tad_probe(struct platform_device *pdev) - if (ret) - goto fail; +diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c +index a506d940a..2766484b8 100644 +--- a/sound/soc/codecs/rt5645.c ++++ b/sound/soc/codecs/rt5645.c +@@ -3717,6 +3717,15 @@ static const struct dmi_system_id dmi_platform_data[] = { + }, + .driver_data = (void *)&intel_braswell_platform_data, + }, ++ { ++ .ident = "Microsoft Surface 3", ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)&intel_braswell_platform_data, ++ }, + { + /* + * 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 cdcbf04b8..958305779 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[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, ++ { ++ .callback = cht_surface_quirk_cb, ++ .matches = { ++ DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ }, + { } + }; -+ if (caps & ACPI_TAD_AC_WAKE) { -+ ret = sysfs_create_group(&dev->kobj, &acpi_tad_ac_attr_group); -+ if (ret) -+ goto fail; -+ } -+ - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) -- 2.41.0 |