diff --git a/configs/surface-5.4.config b/configs/surface-5.4.config new file mode 100644 index 000000000..da9494aef --- /dev/null +++ b/configs/surface-5.4.config @@ -0,0 +1,30 @@ +# +# Surface Aggregator Module +# +CONFIG_GPIO_SYSFS=y # required for SURFACE_SAM_HPS +CONFIG_SURFACE_SAM=m +CONFIG_SURFACE_SAM_SSH=m +CONFIG_SURFACE_SAM_SSH_DEBUG_DEVICE=y +CONFIG_SURFACE_SAM_SAN=m +CONFIG_SURFACE_SAM_VHF=m +CONFIG_SURFACE_SAM_DTX=m +CONFIG_SURFACE_SAM_HPS=m +CONFIG_SURFACE_SAM_SID=m +CONFIG_SURFACE_SAM_SID_GPELID=m +CONFIG_SURFACE_SAM_SID_PERFMODE=m +CONFIG_SURFACE_SAM_SID_VHF=m +CONFIG_SURFACE_SAM_SID_POWER=m + +# +# IPTS touchscreen +# +CONFIG_TOUCHSCREEN_IPTS=m + +# +# Other Drivers +# +CONFIG_INPUT_SOC_BUTTON_ARRAY=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_3_BUTTON=m +CONFIG_SURFACE_3_POWER_OPREGION=m +CONFIG_SURFACE_PRO3_BUTTON=m diff --git a/patches/5.4/0001-surface3-power.patch b/patches/5.4/0001-surface3-power.patch index 426a50362..67ca86fd1 100644 --- a/patches/5.4/0001-surface3-power.patch +++ b/patches/5.4/0001-surface3-power.patch @@ -1,4 +1,4 @@ -From 282a7c0dfafdcd6fecd3fef61353e9d8638752fe Mon Sep 17 00:00:00 2001 +From 776ae5ea12a951312f7fb3d3e69a3e7004eb4f4f Mon Sep 17 00:00:00 2001 From: qzed Date: Tue, 17 Sep 2019 17:17:56 +0200 Subject: [PATCH 1/7] surface3-power @@ -11,7 +11,7 @@ Subject: [PATCH 1/7] surface3-power create mode 100644 drivers/platform/x86/surface3_power.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 1cab99320514..348c795019fa 100644 +index 1cab993205142..348c795019fa4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1209,6 +1209,13 @@ config SURFACE_3_BUTTON @@ -29,7 +29,7 @@ index 1cab99320514..348c795019fa 100644 tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 415104033060..6dd955ad9bf1 100644 +index 4151040330601..6dd955ad9bf18 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -85,6 +85,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o @@ -42,7 +42,7 @@ index 415104033060..6dd955ad9bf1 100644 obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ diff --git a/drivers/platform/x86/surface3_power.c b/drivers/platform/x86/surface3_power.c new file mode 100644 -index 000000000000..e0af01a60302 +index 0000000000000..e0af01a603025 --- /dev/null +++ b/drivers/platform/x86/surface3_power.c @@ -0,0 +1,604 @@ @@ -651,5 +651,5 @@ index 000000000000..e0af01a60302 +MODULE_DESCRIPTION("mshw0011 driver"); +MODULE_LICENSE("GPL v2"); -- -2.25.0 +2.26.2 diff --git a/patches/5.4/0002-surface3-spi.patch b/patches/5.4/0002-surface3-spi.patch index a44e52227..8ef63e142 100644 --- a/patches/5.4/0002-surface3-spi.patch +++ b/patches/5.4/0002-surface3-spi.patch @@ -1,4 +1,4 @@ -From 3e6aef8d1ff405ae075722f3b4a5155b2320a111 Mon Sep 17 00:00:00 2001 +From 549b0062d79c181f68fc4216901db61b0da0f152 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Fri, 6 Dec 2019 23:10:30 +0900 Subject: [PATCH 2/7] surface3-spi @@ -8,7 +8,7 @@ Subject: [PATCH 2/7] surface3-spi 1 file changed, 26 insertions(+) diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c -index ce4828b1415a..63b0b8ddf090 100644 +index ce4828b1415a8..63b0b8ddf0903 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -25,6 +25,12 @@ @@ -59,5 +59,5 @@ index ce4828b1415a..63b0b8ddf090 100644 } -- -2.25.0 +2.26.2 diff --git a/patches/5.4/0003-surface3-oemb.patch b/patches/5.4/0003-surface3-oemb.patch index 8b7fa0ad3..37938f50d 100644 --- a/patches/5.4/0003-surface3-oemb.patch +++ b/patches/5.4/0003-surface3-oemb.patch @@ -1,4 +1,4 @@ -From dfe2385d2165eedba0ca3bb4fb72bb5293c24c62 Mon Sep 17 00:00:00 2001 +From 2399e1d0b248cd799d6103ae6ec69449d5145d54 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Tue, 18 Sep 2018 11:01:37 +0800 Subject: [PATCH 3/7] surface3-oemb @@ -6,11 +6,11 @@ Subject: [PATCH 3/7] surface3-oemb --- drivers/platform/x86/surface3-wmi.c | 7 +++++++ sound/soc/codecs/rt5645.c | 9 +++++++++ - sound/soc/intel/common/soc-acpi-intel-cht-match.c | 6 ++++++ - 3 files changed, 22 insertions(+) + sound/soc/intel/common/soc-acpi-intel-cht-match.c | 8 ++++++++ + 3 files changed, 24 insertions(+) diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c -index 130b6f52a600..801083aa56d6 100644 +index 130b6f52a6001..801083aa56d6d 100644 --- a/drivers/platform/x86/surface3-wmi.c +++ b/drivers/platform/x86/surface3-wmi.c @@ -37,6 +37,13 @@ static const struct dmi_system_id surface3_dmi_table[] = { @@ -28,7 +28,7 @@ index 130b6f52a600..801083aa56d6 100644 { } }; diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c -index 19662ee330d6..dbe70f80d1de 100644 +index 19662ee330d6b..dbe70f80d1de7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3675,6 +3675,15 @@ static const struct dmi_system_id dmi_platform_data[] = { @@ -48,22 +48,24 @@ index 19662ee330d6..dbe70f80d1de 100644 /* * Match for the GPDwin which unfortunately uses somewhat diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -index d0fb43c2b9f6..de2583918afd 100644 +index d0fb43c2b9f68..0e938713cb133 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c -@@ -26,6 +26,12 @@ static const struct dmi_system_id cht_table[] = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), +@@ -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"), + }, - }, ++ }, { } }; + -- -2.25.0 +2.26.2 diff --git a/patches/5.4/0004-ioremap_uc.patch b/patches/5.4/0004-ioremap_uc.patch deleted file mode 100644 index 923be82c7..000000000 --- a/patches/5.4/0004-ioremap_uc.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 83aa487e4c43e598ee3e5266e79573ba6e0a3ab7 Mon Sep 17 00:00:00 2001 -From: Tuowen Zhao -Date: Wed, 16 Oct 2019 15:06:28 -0600 -Subject: [PATCH 4/7] ioremap_uc - ---- - .../driver-api/driver-model/devres.rst | 1 + - drivers/mfd/intel-lpss.c | 2 +- - include/linux/io.h | 2 ++ - lib/devres.c | 19 +++++++++++++++++++ - 4 files changed, 23 insertions(+), 1 deletion(-) - -diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst -index a100bef54952..92628fdc2f11 100644 ---- a/Documentation/driver-api/driver-model/devres.rst -+++ b/Documentation/driver-api/driver-model/devres.rst -@@ -314,6 +314,7 @@ IOMAP - devm_ioport_unmap() - devm_ioremap() - devm_ioremap_nocache() -+ devm_ioremap_uc() - devm_ioremap_wc() - devm_ioremap_resource() : checks resource, requests memory region, ioremaps - devm_iounmap() -diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c -index bfe4ff337581..b0f0781a6b9c 100644 ---- a/drivers/mfd/intel-lpss.c -+++ b/drivers/mfd/intel-lpss.c -@@ -384,7 +384,7 @@ int intel_lpss_probe(struct device *dev, - if (!lpss) - return -ENOMEM; - -- lpss->priv = devm_ioremap(dev, info->mem->start + LPSS_PRIV_OFFSET, -+ lpss->priv = devm_ioremap_uc(dev, info->mem->start + LPSS_PRIV_OFFSET, - LPSS_PRIV_SIZE); - if (!lpss->priv) - return -ENOMEM; -diff --git a/include/linux/io.h b/include/linux/io.h -index accac822336a..a59834bc0a11 100644 ---- a/include/linux/io.h -+++ b/include/linux/io.h -@@ -64,6 +64,8 @@ static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr) - - void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, - resource_size_t size); -+void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset, -+ resource_size_t size); - void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, - resource_size_t size); - void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, -diff --git a/lib/devres.c b/lib/devres.c -index 6a0e9bd6524a..17624d35e82d 100644 ---- a/lib/devres.c -+++ b/lib/devres.c -@@ -9,6 +9,7 @@ - enum devm_ioremap_type { - DEVM_IOREMAP = 0, - DEVM_IOREMAP_NC, -+ DEVM_IOREMAP_UC, - DEVM_IOREMAP_WC, - }; - -@@ -39,6 +40,9 @@ static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset, - case DEVM_IOREMAP_NC: - addr = ioremap_nocache(offset, size); - break; -+ case DEVM_IOREMAP_UC: -+ addr = ioremap_uc(offset, size); -+ break; - case DEVM_IOREMAP_WC: - addr = ioremap_wc(offset, size); - break; -@@ -68,6 +72,21 @@ void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, - } - EXPORT_SYMBOL(devm_ioremap); - -+/** -+ * devm_ioremap_uc - Managed ioremap_uc() -+ * @dev: Generic device to remap IO address for -+ * @offset: Resource address to map -+ * @size: Size of map -+ * -+ * Managed ioremap_uc(). Map is automatically unmapped on driver detach. -+ */ -+void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset, -+ resource_size_t size) -+{ -+ return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_UC); -+} -+EXPORT_SYMBOL_GPL(devm_ioremap_uc); -+ - /** - * devm_ioremap_nocache - Managed ioremap_nocache() - * @dev: Generic device to remap IO address for --- -2.25.0 - diff --git a/patches/5.4/0005-surface-sam.patch b/patches/5.4/0004-surface-sam.patch similarity index 93% rename from patches/5.4/0005-surface-sam.patch rename to patches/5.4/0004-surface-sam.patch index 9b9e24ea5..95754a13d 100644 --- a/patches/5.4/0005-surface-sam.patch +++ b/patches/5.4/0004-surface-sam.patch @@ -1,29 +1,29 @@ -From bab81477b7af1b95845d7a35d418a6395136d434 Mon Sep 17 00:00:00 2001 +From 58d7f7c62d0b37687982b6ed9d891f3420d47e13 Mon Sep 17 00:00:00 2001 From: qzed Date: Mon, 26 Aug 2019 01:11:08 +0200 -Subject: [PATCH 5/7] surface-sam +Subject: [PATCH 4/7] surface-sam --- drivers/acpi/acpica/dsopcode.c | 2 +- drivers/acpi/acpica/exfield.c | 12 +- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/surface_sam/Kconfig | 163 ++ + drivers/platform/x86/surface_sam/Kconfig | 164 ++ drivers/platform/x86/surface_sam/Makefile | 10 + - .../x86/surface_sam/surface_sam_dtx.c | 623 ++++++ + .../x86/surface_sam/surface_sam_dtx.c | 604 ++++++ .../x86/surface_sam/surface_sam_hps.c | 1110 +++++++++++ - .../x86/surface_sam/surface_sam_san.c | 901 +++++++++ - .../x86/surface_sam/surface_sam_san.h | 29 + - .../x86/surface_sam/surface_sam_sid.c | 117 ++ - .../x86/surface_sam/surface_sam_sid_gpelid.c | 219 ++ - .../surface_sam/surface_sam_sid_perfmode.c | 225 +++ - .../x86/surface_sam/surface_sam_sid_power.c | 1259 ++++++++++++ - .../x86/surface_sam/surface_sam_sid_vhf.c | 440 ++++ - .../x86/surface_sam/surface_sam_ssh.c | 1773 +++++++++++++++++ - .../x86/surface_sam/surface_sam_ssh.h | 97 + - .../x86/surface_sam/surface_sam_vhf.c | 276 +++ + .../x86/surface_sam/surface_sam_san.c | 883 +++++++++ + .../x86/surface_sam/surface_sam_san.h | 30 + + .../x86/surface_sam/surface_sam_sid.c | 137 ++ + .../x86/surface_sam/surface_sam_sid_gpelid.c | 224 +++ + .../surface_sam/surface_sam_sid_perfmode.c | 216 ++ + .../x86/surface_sam/surface_sam_sid_power.c | 1264 ++++++++++++ + .../x86/surface_sam/surface_sam_sid_vhf.c | 428 ++++ + .../x86/surface_sam/surface_sam_ssh.c | 1744 +++++++++++++++++ + .../x86/surface_sam/surface_sam_ssh.h | 98 + + .../x86/surface_sam/surface_sam_vhf.c | 270 +++ drivers/tty/serdev/core.c | 111 +- - 19 files changed, 7353 insertions(+), 16 deletions(-) + 19 files changed, 7293 insertions(+), 16 deletions(-) create mode 100644 drivers/platform/x86/surface_sam/Kconfig create mode 100644 drivers/platform/x86/surface_sam/Makefile create mode 100644 drivers/platform/x86/surface_sam/surface_sam_dtx.c @@ -40,7 +40,7 @@ Subject: [PATCH 5/7] surface-sam create mode 100644 drivers/platform/x86/surface_sam/surface_sam_vhf.c diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c -index 10f32b62608e..7b2a4987f050 100644 +index 10f32b62608ee..7b2a4987f0507 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -123,7 +123,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, @@ -53,7 +53,7 @@ index 10f32b62608e..7b2a4987f050 100644 bit_count = (u32) length_desc->integer.value; diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c -index d3d2dbfba680..0b7f617a6e9b 100644 +index d3d2dbfba680c..0b7f617a6e9b1 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -109,6 +109,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, @@ -85,7 +85,7 @@ index d3d2dbfba680..0b7f617a6e9b 100644 buffer_desc = acpi_ut_create_buffer_object(buffer_length); if (!buffer_desc) { diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 348c795019fa..d25067a838a3 100644 +index 348c795019fa4..d25067a838a33 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1342,6 +1342,7 @@ config PCENGINES_APU2 @@ -97,7 +97,7 @@ index 348c795019fa..d25067a838a3 100644 endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 6dd955ad9bf1..19b56f2181eb 100644 +index 6dd955ad9bf18..19b56f2181eb9 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -101,3 +101,4 @@ obj-$(CONFIG_I2C_MULTI_INSTANTIATE) += i2c-multi-instantiate.o @@ -107,23 +107,23 @@ index 6dd955ad9bf1..19b56f2181eb 100644 +obj-$(CONFIG_SURFACE_SAM) += surface_sam/ diff --git a/drivers/platform/x86/surface_sam/Kconfig b/drivers/platform/x86/surface_sam/Kconfig new file mode 100644 -index 000000000000..b4513c234c4d +index 0000000000000..c4556e58b9a58 --- /dev/null +++ b/drivers/platform/x86/surface_sam/Kconfig -@@ -0,0 +1,163 @@ +@@ -0,0 +1,164 @@ +menuconfig SURFACE_SAM -+ depends on ACPI -+ tristate "Microsoft Surface/System Aggregator Module and Platform Drivers" -+ ---help--- -+ Drivers for the Surface/System Aggregator Module (SAM) of Microsoft -+ Surface devices. ++ depends on ACPI ++ tristate "Microsoft Surface/System Aggregator Module and Platform Drivers" ++ help ++ Drivers for the Surface/System Aggregator Module (SAM) of Microsoft ++ Surface devices. + -+ SAM is an embedded controller that provides access to various -+ functionalities on these devices, including battery status, keyboard -+ events (on the Laptops) and many more. ++ SAM is an embedded controller that provides access to various ++ functionalities on these devices, including battery status, keyboard ++ events (on the Laptops) and many more. + -+ Say M/Y here if you have a Microsoft Surface device with a SAM device -+ (i.e. 5th generation or later). ++ Say M/Y here if you have a Microsoft Surface device with a SAM device ++ (i.e. 5th generation or later). + +config SURFACE_SAM_SSH + tristate "Surface Serial Hub Driver" @@ -131,7 +131,7 @@ index 000000000000..b4513c234c4d + depends on SERIAL_DEV_CTRL_TTYPORT + select CRC_CCITT + default m -+ ---help--- ++ help + Surface Serial Hub driver for 5th generation (or later) Microsoft + Surface devices. + @@ -149,7 +149,7 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SSH + depends on SYSFS + default n -+ ---help--- ++ help + Debug device for direct communication with the embedded controller + found on 5th generation (and later) Microsoft Surface devices (e.g. + Book 2, Laptop, Laptop 2, Pro 2017, Pro 6, ...) via sysfs. @@ -160,7 +160,7 @@ index 000000000000..b4513c234c4d + tristate "Surface ACPI Notify Driver" + depends on SURFACE_SAM_SSH + default m -+ ---help--- ++ help + Surface ACPI Notify driver for 5th generation (or later) Microsoft + Surface devices. + @@ -175,7 +175,7 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SSH + depends on HID + default m -+ ---help--- ++ help + Surface Virtual HID Framework driver for 5th generation (or later) + Microsoft Surface devices. + @@ -189,7 +189,7 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SSH + depends on INPUT + default m -+ ---help--- ++ help + Surface Detachment System (DTX) driver for the Microsoft Surface Book + 2. This driver provides support for proper detachment handling in + user-space, status-events relating to the base and support for @@ -205,8 +205,9 @@ index 000000000000..b4513c234c4d + tristate "Surface dGPU Hot-Plug System (dGPU-HPS) Driver" + depends on SURFACE_SAM_SSH + depends on SURFACE_SAM_SAN ++ depends on GPIO_SYSFS + default m -+ ---help--- ++ help + Driver to properly handle hot-plugging and explicit power-on/power-off + of the discrete GPU (dGPU) on the Surface Book 2. + @@ -216,7 +217,7 @@ index 000000000000..b4513c234c4d + tristate "Surface Platform Integration Driver" + depends on SURFACE_SAM_SSH + default m -+ ---help--- ++ help + Surface Platform Integration Driver for the Microsoft Surface Devices. + This driver loads various model-specific sub-drivers, including + battery and keyboard support on 7th generation Surface devices, proper @@ -230,7 +231,7 @@ index 000000000000..b4513c234c4d + tristate "Surface Lid Wakeup Driver" + depends on SURFACE_SAM_SID + default m -+ ---help--- ++ help + Driver to set up device wake-up via lid on Intel-based Microsoft + Surface devices. These devices do not wake up from sleep as their GPE + interrupt is not configured automatically. This driver solves that @@ -243,8 +244,8 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SID + depends on SYSFS + default m -+ ---help--- -+ This driver provides suport for setting performance-modes on Surface ++ help ++ This driver provides support for setting performance-modes on Surface + devices via the perf_mode sysfs attribute. Currently only supports the + Surface Book 2. Performance-modes directly influence the fan-profile + of the device, allowing to choose between higher performance or @@ -257,7 +258,7 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SID + depends on HID + default m -+ ---help--- ++ help + This driver provides support for HID devices connected via the Surface + SAM embedded controller. It provides support for keyboard and touchpad + on the Surface Laptop 3 models. @@ -269,14 +270,14 @@ index 000000000000..b4513c234c4d + depends on SURFACE_SAM_SID + select POWER_SUPPLY + default m -+ ---help--- ++ help + This driver provides support for the battery and AC on 7th generation + Surface devices. + + If you are not sure, say M here. diff --git a/drivers/platform/x86/surface_sam/Makefile b/drivers/platform/x86/surface_sam/Makefile new file mode 100644 -index 000000000000..188975ccde5c +index 0000000000000..188975ccde5ce --- /dev/null +++ b/drivers/platform/x86/surface_sam/Makefile @@ -0,0 +1,10 @@ @@ -292,10 +293,11 @@ index 000000000000..188975ccde5c +obj-$(CONFIG_SURFACE_SAM_SID_VHF) += surface_sam_sid_vhf.o diff --git a/drivers/platform/x86/surface_sam/surface_sam_dtx.c b/drivers/platform/x86/surface_sam/surface_sam_dtx.c new file mode 100644 -index 000000000000..4b924de6ab09 +index 0000000000000..1e772fd5b0bea --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_dtx.c -@@ -0,0 +1,623 @@ +@@ -0,0 +1,604 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Detachment system (DTX) driver for Microsoft Surface Book 2. + */ @@ -415,13 +417,11 @@ index 000000000000..4b924de6ab09 + }; + + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status) { ++ if (status) + return status; -+ } + -+ if (result.len != 1) { ++ if (result.len != 1) + return -EFAULT; -+ } + + return result.data[0]; +} @@ -444,14 +444,14 @@ index 000000000000..4b924de6ab09 + +static int dtx_cmd_get_opmode(int __user *buf) +{ -+ int opmode = surface_sam_query_opmpde(); -+ if (opmode < 0) { -+ return opmode; -+ } ++ int opmode; + -+ if (put_user(opmode, buf)) { ++ opmode = surface_sam_query_opmpde(); ++ if (opmode < 0) ++ return opmode; ++ ++ if (put_user(opmode, buf)) + return -EACCES; -+ } + + return 0; +} @@ -464,9 +464,8 @@ index 000000000000..4b924de6ab09 + + // initialize client + client = kzalloc(sizeof(struct surface_dtx_client), GFP_KERNEL); -+ if (!client) { ++ if (!client) + return -ENOMEM; -+ } + + spin_lock_init(&client->buffer_lock); + client->buffer_head = 0; @@ -508,37 +507,32 @@ index 000000000000..4b924de6ab09 + size_t read = 0; + int status = 0; + -+ if (count != 0 && count < sizeof(struct surface_dtx_event)) { ++ if (count != 0 && count < sizeof(struct surface_dtx_event)) + return -EINVAL; -+ } + -+ if (!ddev->active) { ++ if (!ddev->active) + return -ENODEV; -+ } + + // check availability -+ if (client->buffer_head == client->buffer_tail){ -+ if (file->f_flags & O_NONBLOCK) { ++ if (client->buffer_head == client->buffer_tail) { ++ if (file->f_flags & O_NONBLOCK) + return -EAGAIN; -+ } + + status = wait_event_interruptible(ddev->waitq, + client->buffer_head != client->buffer_tail || + !ddev->active); -+ if (status) { ++ if (status) + return status; -+ } + -+ if (!ddev->active) { ++ if (!ddev->active) + return -ENODEV; -+ } + } + + // copy events one by one + while (read + sizeof(struct surface_dtx_event) <= count) { + spin_lock_irq(&client->buffer_lock); + -+ if(client->buffer_head == client->buffer_tail) { ++ if (client->buffer_head == client->buffer_tail) { + spin_unlock_irq(&client->buffer_lock); + break; + } @@ -549,9 +543,8 @@ index 000000000000..4b924de6ab09 + spin_unlock_irq(&client->buffer_lock); + + // copy to userspace -+ if(copy_to_user(buf, &event, sizeof(struct surface_dtx_event))) { ++ if (copy_to_user(buf, &event, sizeof(struct surface_dtx_event))) + return -EFAULT; -+ } + + read += sizeof(struct surface_dtx_event); + } @@ -566,15 +559,13 @@ index 000000000000..4b924de6ab09 + + poll_wait(file, &client->ddev->waitq, pt); + -+ if (client->ddev->active) { ++ if (client->ddev->active) + mask = EPOLLOUT | EPOLLWRNORM; -+ } else { ++ else + mask = EPOLLHUP | EPOLLERR; -+ } + -+ if (client->buffer_head != client->buffer_tail) { ++ if (client->buffer_head != client->buffer_tail) + mask |= EPOLLIN | EPOLLRDNORM; -+ } + + return mask; +} @@ -593,9 +584,8 @@ index 000000000000..4b924de6ab09 + int status; + + status = mutex_lock_interruptible(&ddev->mutex); -+ if (status) { ++ if (status) + return status; -+ } + + if (!ddev->active) { + mutex_unlock(&ddev->mutex); @@ -689,9 +679,8 @@ index 000000000000..4b924de6ab09 + + // get operation mode + opmode = surface_sam_query_opmpde(); -+ if (opmode < 0) { ++ if (opmode < 0) + printk(DTX_ERR "EC request failed with error %d\n", opmode); -+ } + + // send DTX event + event.type = 0x11; @@ -703,7 +692,7 @@ index 000000000000..4b924de6ab09 + + // send SW_TABLET_MODE event + spin_lock(&ddev->input_lock); -+ input_report_switch(ddev->input_dev, SW_TABLET_MODE, opmode == 0x00); ++ input_report_switch(ddev->input_dev, SW_TABLET_MODE, opmode != DTX_OPMODE_LAPTOP); + input_sync(ddev->input_dev); + spin_unlock(&ddev->input_lock); +} @@ -753,14 +742,12 @@ index 000000000000..4b924de6ab09 + int status; + + status = surface_sam_ssh_set_event_handler(SAM_EVENT_DTX_RQID, surface_dtx_evt_dtx, ddev); -+ if (status) { ++ if (status) + goto err_handler; -+ } + + status = surface_sam_ssh_enable_event_source(SAM_EVENT_DTX_TC, 0x01, SAM_EVENT_DTX_RQID); -+ if (status) { ++ if (status) + goto err_source; -+ } + + return 0; + @@ -783,9 +770,8 @@ index 000000000000..4b924de6ab09 + int status; + + input_dev = input_allocate_device(); -+ if (!input_dev) { ++ if (!input_dev) + return ERR_PTR(-ENOMEM); -+ } + + input_dev->name = DTX_INPUT_NAME; + input_dev->dev.parent = &pdev->dev; @@ -801,7 +787,7 @@ index 000000000000..4b924de6ab09 + return ERR_PTR(status); + } + -+ input_report_switch(input_dev, SW_TABLET_MODE, status == 0x00); ++ input_report_switch(input_dev, SW_TABLET_MODE, status != DTX_OPMODE_LAPTOP); + + status = input_register_device(input_dev); + if (status) { @@ -821,14 +807,12 @@ index 000000000000..4b924de6ab09 + + // link to ec + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + input_dev = surface_dtx_register_inputdev(pdev); -+ if (IS_ERR(input_dev)) { ++ if (IS_ERR(input_dev)) + return PTR_ERR(input_dev); -+ } + + // initialize device + mutex_lock(&ddev->mutex); @@ -845,15 +829,13 @@ index 000000000000..4b924de6ab09 + mutex_unlock(&ddev->mutex); + + status = misc_register(&ddev->mdev); -+ if (status) { ++ if (status) + goto err_register; -+ } + + // enable events + status = surface_dtx_events_setup(ddev); -+ if (status) { ++ if (status) + goto err_events_setup; -+ } + + return 0; + @@ -921,10 +903,11 @@ index 000000000000..4b924de6ab09 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_hps.c b/drivers/platform/x86/surface_sam/surface_sam_hps.c new file mode 100644 -index 000000000000..3b123bd3dcfe +index 0000000000000..4fba5ee75a66f --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_hps.c @@ -0,0 +1,1110 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface dGPU hot-plug system driver. + * Supports explicit setting of the dGPU power-state on the Surface Book 2 and @@ -994,7 +977,8 @@ index 000000000000..3b123bd3dcfe + SHPS_DGPU_POWER_UNKNOWN = 2, +}; + -+static const char* shps_dgpu_power_str(enum shps_dgpu_power power) { ++static const char *shps_dgpu_power_str(enum shps_dgpu_power power) ++{ + if (power == SHPS_DGPU_POWER_OFF) + return "off"; + else if (power == SHPS_DGPU_POWER_ON) @@ -1023,7 +1007,7 @@ index 000000000000..3b123bd3dcfe +#define SHPS_STATE_BIT_WAKE_ENABLED 2 /* wakeup via base-presence GPIO enabled */ + + -+#define SHPS_DGPU_PARAM_PERM (S_IRUGO | S_IWUSR) ++#define SHPS_DGPU_PARAM_PERM 0644 + +enum shps_dgpu_power_mp { + SHPS_DGPU_MP_POWER_OFF = SHPS_DGPU_POWER_OFF, @@ -1040,13 +1024,11 @@ index 000000000000..3b123bd3dcfe + int status; + + status = kstrtoint(val, 0, &power); -+ if (status) { ++ if (status) + return status; -+ } + -+ if (power < __SHPS_DGPU_MP_POWER_START || power > __SHPS_DGPU_MP_POWER_END) { ++ if (power < __SHPS_DGPU_MP_POWER_START || power > __SHPS_DGPU_MP_POWER_END) + return -EINVAL; -+ } + + return param_set_int(val, kp); +} @@ -1087,18 +1069,18 @@ index 000000000000..3b123bd3dcfe + return surface_sam_ssh_rqst(&rqst, NULL); +} + -+inline static int shps_dtx_latch_lock(void) ++static inline int shps_dtx_latch_lock(void) +{ + return dtx_cmd_simple(SAM_DTX_CID_LATCH_LOCK); +} + -+inline static int shps_dtx_latch_unlock(void) ++static inline int shps_dtx_latch_unlock(void) +{ + return dtx_cmd_simple(SAM_DTX_CID_LATCH_UNLOCK); +} + + -+static int shps_dgpu_dsm_get_pci_addr(struct platform_device *pdev, const char* entry) ++static int shps_dgpu_dsm_get_pci_addr(struct platform_device *pdev, const char *entry) +{ + acpi_handle handle = ACPI_HANDLE(&pdev->dev); + union acpi_object *result; @@ -1152,7 +1134,7 @@ index 000000000000..3b123bd3dcfe + return bus << 8 | PCI_DEVFN(dev, fun); +} + -+static struct pci_dev *shps_dgpu_dsm_get_pci_dev(struct platform_device *pdev, const char* entry) ++static struct pci_dev *shps_dgpu_dsm_get_pci_dev(struct platform_device *pdev, const char *entry) +{ + struct pci_dev *dev; + int addr; @@ -1203,7 +1185,7 @@ index 000000000000..3b123bd3dcfe + param.integer.value = power == SHPS_DGPU_POWER_ON; + + result = acpi_evaluate_dsm_typed(handle, &SHPS_DSM_UUID, SHPS_DSM_REVISION, -+ SHPS_DSM_GPU_POWER, ¶m, ACPI_TYPE_BUFFER); ++ SHPS_DSM_GPU_POWER, ¶m, ACPI_TYPE_BUFFER); + + if (IS_ERR_OR_NULL(result)) + return result ? PTR_ERR(result) : -EIO; @@ -1388,20 +1370,23 @@ index 000000000000..3b123bd3dcfe + if (status) + shps_dtx_latch_unlock(); + -+ return status; + } else { + status = shps_dgpu_rp_set_power(pdev, power); + if (status) + return status; + -+ return shps_dtx_latch_unlock(); ++ status = shps_dtx_latch_unlock(); + } ++ ++ return status; +} + + +static int shps_dgpu_is_present(struct platform_device *pdev) +{ -+ struct shps_driver_data *drvdata = platform_get_drvdata(pdev); ++ struct shps_driver_data *drvdata; ++ ++ drvdata = platform_get_drvdata(pdev); + return gpiod_get_value_cansleep(drvdata->gpio_dgpu_presence); +} + @@ -1629,9 +1614,8 @@ index 000000000000..3b123bd3dcfe + struct shps_driver_data *drvdata = platform_get_drvdata(pdev); + int status = 0; + -+ if (test_and_clear_bit(SHPS_STATE_BIT_WAKE_ENABLED, &drvdata->state)) { ++ if (test_and_clear_bit(SHPS_STATE_BIT_WAKE_ENABLED, &drvdata->state)) + status = disable_irq_wake(drvdata->irq_base_presence); -+ } + + return status; +} @@ -1903,15 +1887,13 @@ index 000000000000..3b123bd3dcfe + + // link to SSH + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + // link to SAN + status = surface_sam_san_consumer_register(&pdev->dev, 0); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + status = acpi_dev_add_driver_gpios(shps_dev, shps_acpi_gpios); + if (status) @@ -2020,7 +2002,7 @@ index 000000000000..3b123bd3dcfe +}; +MODULE_DEVICE_TABLE(acpi, shps_acpi_match); + -+struct platform_driver surface_sam_hps = { ++static struct platform_driver surface_sam_hps = { + .probe = shps_probe, + .remove = shps_remove, + .shutdown = shps_shutdown, @@ -2037,10 +2019,11 @@ index 000000000000..3b123bd3dcfe +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_san.c b/drivers/platform/x86/surface_sam/surface_sam_san.c new file mode 100644 -index 000000000000..aa0cfc4262be +index 0000000000000..63478945e6b26 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_san.c -@@ -0,0 +1,901 @@ +@@ -0,0 +1,883 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface ACPI Notify (SAN) and ACPI integration driver for SAM. + * Translates communication from ACPI to SSH and back. @@ -2063,7 +2046,7 @@ index 000000000000..aa0cfc4262be + +static const guid_t SAN_DSM_UUID = + GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d, -+ 0x48, 0x7c, 0x91, 0xab, 0x3c); ++ 0x48, 0x7c, 0x91, 0xab, 0x3c); + +#define SAM_EVENT_DELAY_PWR_ADAPTER msecs_to_jiffies(5000) +#define SAM_EVENT_DELAY_PWR_BST msecs_to_jiffies(2500) @@ -2245,11 +2228,10 @@ index 000000000000..aa0cfc4262be + + dev_dbg(dev, "notify power event 0x%02x\n", event); + obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, -+ (u8) event, NULL, ACPI_TYPE_BUFFER); ++ (u8) event, NULL, ACPI_TYPE_BUFFER); + -+ if (IS_ERR_OR_NULL(obj)) { ++ if (IS_ERR_OR_NULL(obj)) + return obj ? PTR_ERR(obj) : -ENXIO; -+ } + + if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { + dev_err(dev, "got unexpected result from _DSM\n"); @@ -2270,12 +2252,11 @@ index 000000000000..aa0cfc4262be + param.integer.value = iid; + + obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, -+ SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT, ++ SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT, + ¶m, ACPI_TYPE_BUFFER); + -+ if (IS_ERR_OR_NULL(obj)) { ++ if (IS_ERR_OR_NULL(obj)) + return obj ? PTR_ERR(obj) : -ENXIO; -+ } + + if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { + dev_err(dev, "got unexpected result from _DSM\n"); @@ -2287,7 +2268,7 @@ index 000000000000..aa0cfc4262be +} + + -+inline static int san_evt_power_adapter(struct device *dev, struct surface_sam_ssh_event *event) ++static inline int san_evt_power_adapter(struct device *dev, struct surface_sam_ssh_event *event) +{ + int status; + @@ -2319,16 +2300,15 @@ index 000000000000..aa0cfc4262be + return 0; +} + -+inline static int san_evt_power_bix(struct device *dev, struct surface_sam_ssh_event *event) ++static inline int san_evt_power_bix(struct device *dev, struct surface_sam_ssh_event *event) +{ + enum san_pwr_event evcode; + int status; + -+ if (event->iid == 0x02) { ++ if (event->iid == 0x02) + evcode = SAN_PWR_EVENT_BAT2_INFO; -+ } else { ++ else + evcode = SAN_PWR_EVENT_BAT1_INFO; -+ } + + status = san_acpi_notify_power_event(dev, evcode); + if (status) { @@ -2339,16 +2319,15 @@ index 000000000000..aa0cfc4262be + return 0; +} + -+inline static int san_evt_power_bst(struct device *dev, struct surface_sam_ssh_event *event) ++static inline int san_evt_power_bst(struct device *dev, struct surface_sam_ssh_event *event) +{ + enum san_pwr_event evcode; + int status; + -+ if (event->iid == 0x02) { ++ if (event->iid == 0x02) + evcode = SAN_PWR_EVENT_BAT2_STAT; -+ } else { ++ else + evcode = SAN_PWR_EVENT_BAT1_STAT; -+ } + + status = san_acpi_notify_power_event(dev, evcode); + if (status) { @@ -2414,7 +2393,7 @@ index 000000000000..aa0cfc4262be +} + + -+inline static int san_evt_thermal_notify(struct device *dev, struct surface_sam_ssh_event *event) ++static inline int san_evt_thermal_notify(struct device *dev, struct surface_sam_ssh_event *event) +{ + int status; + @@ -2499,9 +2478,8 @@ index 000000000000..aa0cfc4262be + int status = 0; + int try; + -+ if (!gsb_rqst) { ++ if (!gsb_rqst) + return AE_OK; -+ } + + rqst.tc = gsb_rqst->tc; + rqst.cid = gsb_rqst->cid; @@ -2515,17 +2493,16 @@ index 000000000000..aa0cfc4262be + result.len = 0; + result.data = kzalloc(result.cap, GFP_KERNEL); + -+ if (!result.data) { ++ if (!result.data) + return AE_NO_MEMORY; -+ } + + for (try = 0; try < SAN_RQST_RETRY; try++) { -+ if (try) { -+ dev_warn(ctx->dev, SAN_RQST_TAG "IO error occured, trying again\n"); -+ } ++ if (try) ++ dev_warn(ctx->dev, SAN_RQST_TAG "IO error occurred, trying again\n"); + + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status != -EIO) break; ++ if (status != -EIO) ++ break; + } + + if (rqst.tc == 0x11 && rqst.cid == 0x0D && status == -EPERM) { @@ -2577,9 +2554,8 @@ index 000000000000..aa0cfc4262be + struct surface_sam_san_rqsg rqsg = {}; + int status; + -+ if (!gsb_rqsg) { ++ if (!gsb_rqsg) + return AE_OK; -+ } + + rqsg.tc = gsb_rqsg->tc; + rqsg.cid = gsb_rqsg->cid; @@ -2740,22 +2716,19 @@ index 000000000000..aa0cfc4262be + u32 max_links = 0; + int status; + -+ if (!cons) { ++ if (!cons) + return 0; -+ } + + // count links -+ for (con = cons; con->path; ++con) { ++ for (con = cons; con->path; ++con) + max_links += 1; -+ } + + // allocate -+ links = kzalloc(max_links * sizeof(struct san_consumer_link), GFP_KERNEL); ++ links = kcalloc(max_links, sizeof(struct san_consumer_link), GFP_KERNEL); + link = &links[0]; + -+ if (!links) { ++ if (!links) + return -ENOMEM; -+ } + + // create links + for (con = cons; con->path; ++con) { @@ -2770,9 +2743,8 @@ index 000000000000..aa0cfc4262be + } + + status = acpi_bus_get_device(handle, &adev); -+ if (status) { ++ if (status) + goto cleanup; -+ } + + link->link = device_link_add(&adev->dev, &pdev->dev, con->flags); + if (!(link->link)) { @@ -2791,25 +2763,23 @@ index 000000000000..aa0cfc4262be + +cleanup: + for (link = link - 1; link >= links; --link) { -+ if (link->properties->flags & DL_FLAG_STATELESS) { ++ if (link->properties->flags & DL_FLAG_STATELESS) + device_link_del(link->link); -+ } + } + + return status; +} + -+static void san_consumers_unlink(struct san_consumers *consumers) { ++static void san_consumers_unlink(struct san_consumers *consumers) ++{ + u32 i; + -+ if (!consumers) { ++ if (!consumers) + return; -+ } + + for (i = 0; i < consumers->num; ++i) { -+ if (consumers->links[i].properties->flags & DL_FLAG_STATELESS) { ++ if (consumers->links[i].properties->flags & DL_FLAG_STATELESS) + device_link_del(consumers->links[i].link); -+ } + } + + kfree(consumers->links); @@ -2832,22 +2802,19 @@ index 000000000000..aa0cfc4262be + * consumer to set up a device_link. + */ + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + drvdata = kzalloc(sizeof(struct san_drvdata), GFP_KERNEL); -+ if (!drvdata) { ++ if (!drvdata) + return -ENOMEM; -+ } + + drvdata->opreg_ctx.dev = &pdev->dev; + + cons = acpi_device_get_match_data(&pdev->dev); + status = san_consumers_link(pdev, cons, &drvdata->consumers); -+ if (status) { ++ if (status) + goto err_consumers; -+ } + + platform_set_drvdata(pdev, drvdata); + @@ -2862,21 +2829,18 @@ index 000000000000..aa0cfc4262be + } + + status = san_enable_events(pdev); -+ if (status) { ++ if (status) + goto err_enable_events; -+ } + + mutex_lock(&rqsg_if.lock); -+ if (!rqsg_if.san_dev) { ++ if (!rqsg_if.san_dev) + rqsg_if.san_dev = &pdev->dev; -+ } else { ++ else + status = -EBUSY; -+ } + mutex_unlock(&rqsg_if.lock); + -+ if (status) { ++ if (status) + goto err_install_dev; -+ } + + acpi_walk_dep_device_list(san); + return 0; @@ -2923,7 +2887,7 @@ index 000000000000..aa0cfc4262be +}; + +static const struct acpi_device_id surface_sam_san_match[] = { -+ { "MSHW0091", (long unsigned int) san_mshw0091_consumers }, ++ { "MSHW0091", (unsigned long) san_mshw0091_consumers }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, surface_sam_san_match); @@ -2944,10 +2908,11 @@ index 000000000000..aa0cfc4262be +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_san.h b/drivers/platform/x86/surface_sam/surface_sam_san.h new file mode 100644 -index 000000000000..1ea8713db367 +index 0000000000000..85b6d65699472 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_san.h -@@ -0,0 +1,29 @@ +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Interface for Surface ACPI/Notify (SAN). + * @@ -2967,7 +2932,7 @@ index 000000000000..1ea8713db367 + u8 tc; // target category + u8 cid; // command ID + u8 iid; // instance ID -+ u8 cdl; // command data length (lenght of payload) ++ u8 cdl; // command data length (length of payload) + u8 *pld; // pointer to payload of length cdl +}; + @@ -2979,10 +2944,11 @@ index 000000000000..1ea8713db367 +#endif /* _SURFACE_SAM_SAN_H */ diff --git a/drivers/platform/x86/surface_sam/surface_sam_sid.c b/drivers/platform/x86/surface_sam/surface_sam_sid.c new file mode 100644 -index 000000000000..f64dcd590494 +index 0000000000000..fb49d0e00808e --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_sid.c -@@ -0,0 +1,117 @@ +@@ -0,0 +1,137 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface Integration Driver. + * MFD driver to provide device/model dependent functionality. @@ -2996,14 +2962,16 @@ index 000000000000..f64dcd590494 + + +static const struct mfd_cell sid_devs_sp4[] = { -+ { .name = "surface_sam_sid_gpelid", .id = -1 }, ++ { .name = "surface_sam_sid_gpelid", .id = -1 }, ++ { .name = "surface_sam_sid_perfmode", .id = -1 }, + { }, +}; + +static const struct mfd_cell sid_devs_sp7[] = { -+ { .name = "surface_sam_sid_gpelid", .id = -1 }, -+ { .name = "surface_sam_sid_ac", .id = -1 }, -+ { .name = "surface_sam_sid_battery", .id = -1 }, ++ { .name = "surface_sam_sid_gpelid", .id = -1 }, ++ { .name = "surface_sam_sid_ac", .id = -1 }, ++ { .name = "surface_sam_sid_battery", .id = -1 }, ++ { .name = "surface_sam_sid_perfmode", .id = -1 }, + { }, +}; + @@ -3029,10 +2997,11 @@ index 000000000000..f64dcd590494 +}; + +static const struct mfd_cell sid_devs_sl3_13[] = { -+ { .name = "surface_sam_sid_gpelid", .id = -1 }, -+ { .name = "surface_sam_sid_vhf", .id = -1 }, -+ { .name = "surface_sam_sid_ac", .id = -1 }, -+ { .name = "surface_sam_sid_battery", .id = -1 }, ++ { .name = "surface_sam_sid_gpelid", .id = -1 }, ++ { .name = "surface_sam_sid_vhf", .id = -1 }, ++ { .name = "surface_sam_sid_ac", .id = -1 }, ++ { .name = "surface_sam_sid_battery", .id = -1 }, ++ { .name = "surface_sam_sid_perfmode", .id = -1 }, + { }, +}; + @@ -3044,14 +3013,30 @@ index 000000000000..f64dcd590494 +}; + +static const struct acpi_device_id surface_sam_sid_match[] = { -+ { "MSHW0081", (unsigned long)sid_devs_sp4 }, /* Surface Pro 4, 5, and 6 */ -+ { "MSHW0116", (unsigned long)sid_devs_sp7 }, /* Surface Pro 7 */ -+ { "MSHW0080", (unsigned long)sid_devs_sb1 }, /* Surface Book 1 */ -+ { "MSHW0107", (unsigned long)sid_devs_sb2 }, /* Surface Book 2 */ -+ { "MSHW0086", (unsigned long)sid_devs_sl1 }, /* Surface Laptop 1 */ -+ { "MSHW0112", (unsigned long)sid_devs_sl2 }, /* Surface Laptop 2 */ -+ { "MSHW0114", (unsigned long)sid_devs_sl3_13 }, /* Surface Laptop 3 (13") */ -+ { "MSHW0110", (unsigned long)sid_devs_sl3_15 }, /* Surface Laptop 3 (15") */ ++ /* Surface Pro 4, 5, and 6 */ ++ { "MSHW0081", (unsigned long)sid_devs_sp4 }, ++ ++ /* Surface Pro 7 */ ++ { "MSHW0116", (unsigned long)sid_devs_sp7 }, ++ ++ /* Surface Book 1 */ ++ { "MSHW0080", (unsigned long)sid_devs_sb1 }, ++ ++ /* Surface Book 2 */ ++ { "MSHW0107", (unsigned long)sid_devs_sb2 }, ++ ++ /* Surface Laptop 1 */ ++ { "MSHW0086", (unsigned long)sid_devs_sl1 }, ++ ++ /* Surface Laptop 2 */ ++ { "MSHW0112", (unsigned long)sid_devs_sl2 }, ++ ++ /* Surface Laptop 3 (13") */ ++ { "MSHW0114", (unsigned long)sid_devs_sl3_13 }, ++ ++ /* Surface Laptop 3 (15") */ ++ { "MSHW0110", (unsigned long)sid_devs_sl3_15 }, ++ + { }, +}; +MODULE_DEVICE_TABLE(acpi, surface_sam_sid_match); @@ -3102,10 +3087,11 @@ index 000000000000..f64dcd590494 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_sid_gpelid.c b/drivers/platform/x86/surface_sam/surface_sam_sid_gpelid.c new file mode 100644 -index 000000000000..ce32ebf4d94d +index 0000000000000..286411701d369 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_sid_gpelid.c -@@ -0,0 +1,219 @@ +@@ -0,0 +1,224 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface Lid driver to enable wakeup from suspend via the lid. + */ @@ -3246,25 +3232,29 @@ index 000000000000..ce32ebf4d94d + +static int surface_sam_sid_gpelid_suspend(struct device *dev) +{ -+ const struct sid_lid_device *ldev = dev_get_drvdata(dev); ++ const struct sid_lid_device *ldev; ++ ++ ldev = dev_get_drvdata(dev); + return sid_lid_enable_wakeup(ldev, true); +} + +static int surface_sam_sid_gpelid_resume(struct device *dev) +{ -+ const struct sid_lid_device *ldev = dev_get_drvdata(dev); ++ const struct sid_lid_device *ldev; ++ ++ ldev = dev_get_drvdata(dev); + return sid_lid_enable_wakeup(ldev, false); +} + +static SIMPLE_DEV_PM_OPS(surface_sam_sid_gpelid_pm, -+ surface_sam_sid_gpelid_suspend, -+ surface_sam_sid_gpelid_resume); ++ surface_sam_sid_gpelid_suspend, ++ surface_sam_sid_gpelid_resume); + + +static int surface_sam_sid_gpelid_probe(struct platform_device *pdev) +{ + const struct dmi_system_id *match; -+ struct sid_lid_device *dev; ++ struct sid_lid_device *dev; + acpi_handle lid_handle; + int status; + @@ -3272,9 +3262,9 @@ index 000000000000..ce32ebf4d94d + if (!match) + return -ENODEV; + -+ dev = match->driver_data; -+ if (!dev) -+ return -ENODEV; ++ dev = match->driver_data; ++ if (!dev) ++ return -ENODEV; + + status = acpi_get_handle(NULL, (acpi_string)dev->acpi_path, &lid_handle); + if (status) @@ -3291,11 +3281,11 @@ index 000000000000..ce32ebf4d94d + status = sid_lid_enable_wakeup(dev, false); + if (status) { + acpi_disable_gpe(NULL, dev->gpe_number); -+ return status; -+ } ++ return status; ++ } + -+ platform_set_drvdata(pdev, dev); -+ return 0; ++ platform_set_drvdata(pdev, dev); ++ return 0; +} + +static int surface_sam_sid_gpelid_remove(struct platform_device *pdev) @@ -3304,10 +3294,10 @@ index 000000000000..ce32ebf4d94d + + /* restore default behavior without this module */ + sid_lid_enable_wakeup(dev, false); -+ acpi_disable_gpe(NULL, dev->gpe_number); ++ acpi_disable_gpe(NULL, dev->gpe_number); + -+ platform_set_drvdata(pdev, NULL); -+ return 0; ++ platform_set_drvdata(pdev, NULL); ++ return 0; +} + +static struct platform_driver surface_sam_sid_gpelid = { @@ -3327,10 +3317,11 @@ index 000000000000..ce32ebf4d94d +MODULE_ALIAS("platform:surface_sam_sid_gpelid"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_sid_perfmode.c b/drivers/platform/x86/surface_sam/surface_sam_sid_perfmode.c new file mode 100644 -index 000000000000..880a2567cf1b +index 0000000000000..f74e2b51604d0 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_sid_perfmode.c -@@ -0,0 +1,225 @@ +@@ -0,0 +1,216 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface Performance Mode Driver. + * Allows to change cooling capabilities based on user preference. @@ -3344,7 +3335,7 @@ index 000000000000..880a2567cf1b +#include "surface_sam_ssh.h" + + -+#define SID_PARAM_PERM (S_IRUGO | S_IWUSR) ++#define SID_PARAM_PERM 0644 + +enum sam_perf_mode { + SAM_PERF_MODE_NORMAL = 1, @@ -3390,13 +3381,11 @@ index 000000000000..880a2567cf1b + }; + + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status) { ++ if (status) + return status; -+ } + -+ if (result.len != 8) { ++ if (result.len != 8) + return -EFAULT; -+ } + + return get_unaligned_le32(&result.data[0]); +} @@ -3415,9 +3404,8 @@ index 000000000000..880a2567cf1b + .pld = payload, + }; + -+ if (perf_mode < __SAM_PERF_MODE__START || perf_mode > __SAM_PERF_MODE__END) { ++ if (perf_mode < __SAM_PERF_MODE__START || perf_mode > __SAM_PERF_MODE__END) + return -EINVAL; -+ } + + put_unaligned_le32(perf_mode, &rqst.pld[0]); + return surface_sam_ssh_rqst(&rqst, NULL); @@ -3430,13 +3418,11 @@ index 000000000000..880a2567cf1b + int status; + + status = kstrtoint(val, 0, &perf_mode); -+ if (status) { ++ if (status) + return status; -+ } + -+ if (perf_mode < __SID_PARAM_PERF_MODE__START || perf_mode > __SID_PARAM_PERF_MODE__END) { ++ if (perf_mode < __SID_PARAM_PERF_MODE__START || perf_mode > __SID_PARAM_PERF_MODE__END) + return -EINVAL; -+ } + + return param_set_int(val, kp); +} @@ -3470,20 +3456,18 @@ index 000000000000..880a2567cf1b +} + +static ssize_t perf_mode_store(struct device *dev, struct device_attribute *attr, -+ const char *data, size_t count) ++ const char *data, size_t count) +{ + int perf_mode; + int status; + + status = kstrtoint(data, 0, &perf_mode); -+ if (status) { ++ if (status) + return status; -+ } + + status = surface_sam_perf_mode_set(perf_mode); -+ if (status) { ++ if (status) + return status; -+ } + + // TODO: Should we notify ACPI here? + // @@ -3510,23 +3494,20 @@ index 000000000000..880a2567cf1b + + // link to ec + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + // set initial perf_mode + if (param_perf_mode_init != SID_PARAM_PERF_MODE_AS_IS) { + status = surface_sam_perf_mode_set(param_perf_mode_init); -+ if (status) { ++ if (status) + return status; -+ } + } + + // register perf_mode attribute + status = sysfs_create_file(&pdev->dev.kobj, &dev_attr_perf_mode.attr); -+ if (status) { ++ if (status) + goto err_sysfs; -+ } + + return 0; + @@ -3558,10 +3539,11 @@ index 000000000000..880a2567cf1b +MODULE_ALIAS("platform:surface_sam_sid_perfmode"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_sid_power.c b/drivers/platform/x86/surface_sam/surface_sam_sid_power.c new file mode 100644 -index 000000000000..1f2c88eda394 +index 0000000000000..eb925bdda8837 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_sid_power.c -@@ -0,0 +1,1259 @@ +@@ -0,0 +1,1264 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface SID Battery/AC Driver. + * Provides support for the battery and AC on 7th generation Surface devices. @@ -3895,7 +3877,7 @@ index 000000000000..1f2c88eda394 +struct spwr_subsystem { + struct mutex lock; + -+ unsigned refcount; ++ unsigned int refcount; + struct spwr_ac_device *ac; + struct spwr_battery_device *battery[__SPWR_NUM_BAT]; +}; @@ -3951,18 +3933,18 @@ index 000000000000..1f2c88eda394 +static int spwr_battery_unregister(struct spwr_battery_device *bat); + + -+inline static bool spwr_battery_present(struct spwr_battery_device *bat) ++static inline bool spwr_battery_present(struct spwr_battery_device *bat) +{ + return bat->sta & SAM_BATTERY_STA_PRESENT; +} + + -+inline static int spwr_battery_load_sta(struct spwr_battery_device *bat) ++static inline int spwr_battery_load_sta(struct spwr_battery_device *bat) +{ + return sam_psy_get_sta(bat->id + 1, &bat->sta); +} + -+inline static int spwr_battery_load_bix(struct spwr_battery_device *bat) ++static inline int spwr_battery_load_bix(struct spwr_battery_device *bat) +{ + if (!spwr_battery_present(bat)) + return 0; @@ -3970,7 +3952,7 @@ index 000000000000..1f2c88eda394 + return sam_psy_get_bix(bat->id + 1, &bat->bix); +} + -+inline static int spwr_battery_load_bst(struct spwr_battery_device *bat) ++static inline int spwr_battery_load_bst(struct spwr_battery_device *bat) +{ + if (!spwr_battery_present(bat)) + return 0; @@ -3979,13 +3961,13 @@ index 000000000000..1f2c88eda394 +} + + -+inline static int spwr_battery_set_alarm_unlocked(struct spwr_battery_device *bat, u32 value) ++static inline int spwr_battery_set_alarm_unlocked(struct spwr_battery_device *bat, u32 value) +{ + bat->alarm = value; + return sam_psy_set_btp(bat->id + 1, bat->alarm); +} + -+inline static int spwr_battery_set_alarm(struct spwr_battery_device *bat, u32 value) ++static inline int spwr_battery_set_alarm(struct spwr_battery_device *bat, u32 value) +{ + int status; + @@ -3996,7 +3978,7 @@ index 000000000000..1f2c88eda394 + return status; +} + -+inline static int spwr_battery_update_bst_unlocked(struct spwr_battery_device *bat, bool cached) ++static inline int spwr_battery_update_bst_unlocked(struct spwr_battery_device *bat, bool cached) +{ + unsigned long cache_deadline = bat->timestamp + msecs_to_jiffies(cache_time); + int status; @@ -4027,7 +4009,7 @@ index 000000000000..1f2c88eda394 + return status; +} + -+inline static int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat) ++static inline int spwr_battery_update_bix_unlocked(struct spwr_battery_device *bat) +{ + int status; + @@ -4058,7 +4040,7 @@ index 000000000000..1f2c88eda394 + return status; +} + -+inline static int spwr_ac_update_unlocked(struct spwr_ac_device *ac) ++static inline int spwr_ac_update_unlocked(struct spwr_ac_device *ac) +{ + return sam_psy_get_psrc(0x00, &ac->state); +} @@ -4236,7 +4218,7 @@ index 000000000000..1f2c88eda394 +} + + -+inline static int spwr_battery_prop_status(struct spwr_battery_device *bat) ++static inline int spwr_battery_prop_status(struct spwr_battery_device *bat) +{ + if (bat->bst.state & SAM_BATTERY_STATE_DISCHARGING) + return POWER_SUPPLY_STATUS_DISCHARGING; @@ -4253,7 +4235,7 @@ index 000000000000..1f2c88eda394 + return POWER_SUPPLY_STATUS_UNKNOWN; +} + -+inline static int spwr_battery_prop_technology(struct spwr_battery_device *bat) ++static inline int spwr_battery_prop_technology(struct spwr_battery_device *bat) +{ + if (!strcasecmp("NiCd", bat->bix.type)) + return POWER_SUPPLY_TECHNOLOGY_NiCd; @@ -4273,7 +4255,7 @@ index 000000000000..1f2c88eda394 + return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; +} + -+inline static int spwr_battery_prop_capacity(struct spwr_battery_device *bat) ++static inline int spwr_battery_prop_capacity(struct spwr_battery_device *bat) +{ + if (bat->bst.remaining_cap && bat->bix.last_full_charge_cap) + return bat->bst.remaining_cap * 100 / bat->bix.last_full_charge_cap; @@ -4281,7 +4263,7 @@ index 000000000000..1f2c88eda394 + return 0; +} + -+inline static int spwr_battery_prop_capacity_level(struct spwr_battery_device *bat) ++static inline int spwr_battery_prop_capacity_level(struct spwr_battery_device *bat) +{ + if (bat->bst.state & SAM_BATTERY_STATE_CRITICAL) + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; @@ -4463,14 +4445,12 @@ index 000000000000..1f2c88eda394 + int status; + + status = surface_sam_ssh_set_event_handler(SAM_PWR_RQID, spwr_handle_event, NULL); -+ if (status) { ++ if (status) + goto err_handler; -+ } + + status = surface_sam_ssh_enable_event_source(SAM_PWR_TC, 0x01, SAM_PWR_RQID); -+ if (status) { ++ if (status) + goto err_source; -+ } + + return 0; + @@ -4675,7 +4655,7 @@ index 000000000000..1f2c88eda394 + int status; + + if (bat->id < 0 || bat->id >= __SPWR_NUM_BAT) -+ return -EINVAL ; ++ return -EINVAL; + + mutex_lock(&spwr_subsystem.lock); + if (spwr_subsystem.battery[bat->id] != bat) { @@ -4704,7 +4684,9 @@ index 000000000000..1f2c88eda394 +#ifdef CONFIG_PM_SLEEP +static int surface_sam_sid_battery_resume(struct device *dev) +{ -+ struct spwr_battery_device *bat = dev_get_drvdata(dev); ++ struct spwr_battery_device *bat; ++ ++ bat = dev_get_drvdata(dev); + return spwr_battery_recheck(bat); +} +#else @@ -4733,7 +4715,9 @@ index 000000000000..1f2c88eda394 + +static int surface_sam_sid_battery_remove(struct platform_device *pdev) +{ -+ struct spwr_battery_device *bat = platform_get_drvdata(pdev); ++ struct spwr_battery_device *bat; ++ ++ bat = platform_get_drvdata(pdev); + return spwr_battery_unregister(bat); +} + @@ -4776,7 +4760,9 @@ index 000000000000..1f2c88eda394 + +static int surface_sam_sid_ac_remove(struct platform_device *pdev) +{ -+ struct spwr_ac_device *ac = platform_get_drvdata(pdev); ++ struct spwr_ac_device *ac; ++ ++ ac = platform_get_drvdata(pdev); + return spwr_ac_unregister(ac); +} + @@ -4823,10 +4809,11 @@ index 000000000000..1f2c88eda394 +MODULE_ALIAS("platform:surface_sam_sid_battery"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_sid_vhf.c b/drivers/platform/x86/surface_sam/surface_sam_sid_vhf.c new file mode 100644 -index 000000000000..dc5be3a14a8c +index 0000000000000..9cf912a441717 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_sid_vhf.c -@@ -0,0 +1,440 @@ +@@ -0,0 +1,428 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Microsofs Surface HID (VHF) driver for HID input events via SAM. + * Used for keyboard input events on the 7th generation Surface Laptops. @@ -4950,19 +4937,18 @@ index 000000000000..dc5be3a14a8c + .pri = 0x02, + .snc = 0x01, + .cdl = sizeof(struct surface_sam_sid_vhf_meta_rqst), -+ .pld = (u8*)&resp.rqst, ++ .pld = (u8 *)&resp.rqst, + }; + + struct surface_sam_ssh_buf result = { + .cap = sizeof(struct surface_sam_sid_vhf_meta_resp), + .len = 0, -+ .data = (u8*)&resp, ++ .data = (u8 *)&resp, + }; + + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status) { ++ if (status) + return status; -+ } + + *meta = resp.data.meta; + @@ -4990,20 +4976,19 @@ index 000000000000..dc5be3a14a8c + .pri = 0x02, + .snc = 0x01, + .cdl = sizeof(struct surface_sam_sid_vhf_meta_rqst), -+ .pld = (u8*)&resp.rqst, ++ .pld = (u8 *)&resp.rqst, + }; + + struct surface_sam_ssh_buf result = { + .cap = sizeof(struct surface_sam_sid_vhf_meta_resp), + .len = 0, -+ .data = (u8*)&resp, ++ .data = (u8 *)&resp, + }; + + // first fetch 00 to get the total length + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status) { ++ if (status) + return status; -+ } + + len = resp.data.info.hid_len; + @@ -5100,8 +5085,8 @@ index 000000000000..dc5be3a14a8c + rqst.pri = SURFACE_SAM_PRIORITY_HIGH; + rqst.iid = 0x00; // windows tends to distinguish iids, but EC will take it + rqst.cid = cid; -+ rqst.snc = HID_REQ_GET_REPORT == reqtype ? 0x01 : 0x00; -+ rqst.cdl = HID_REQ_GET_REPORT == reqtype ? 0x01 : len; ++ rqst.snc = reqtype == HID_REQ_GET_REPORT ? 0x01 : 0x00; ++ rqst.cdl = reqtype == HID_REQ_GET_REPORT ? 0x01 : len; + rqst.pld = buf; + + result.cap = len; @@ -5113,13 +5098,11 @@ index 000000000000..dc5be3a14a8c + status = surface_sam_ssh_rqst(&rqst, &result); + hid_dbg(hid, "%s: status %i\n", __func__, status); + -+ if (status) { ++ if (status) + return status; -+ } + -+ if (result.len > 0) { ++ if (result.len > 0) + print_hex_dump_debug("response:", DUMP_PREFIX_OFFSET, 16, 1, result.data, result.len, false); -+ } + + return result.len; +} @@ -5139,9 +5122,8 @@ index 000000000000..dc5be3a14a8c + struct hid_device *hid; + + hid = hid_allocate_device(); -+ if (IS_ERR(hid)) { ++ if (IS_ERR(hid)) + return hid; -+ } + + hid->dev.parent = &pdev->dev; + @@ -5161,13 +5143,11 @@ index 000000000000..dc5be3a14a8c + struct sid_vhf_evtctx *ctx = (struct sid_vhf_evtctx *)data; + + // skip if HID hasn't started yet -+ if (!test_bit(VHF_HID_STARTED, &ctx->flags)) { ++ if (!test_bit(VHF_HID_STARTED, &ctx->flags)) + return 0; -+ } + -+ if (event->tc == SAM_EVENT_SID_VHF_TC && (event->cid == 0x00 || event->cid == 0x03 || event->cid == 0x04)) { ++ if (event->tc == SAM_EVENT_SID_VHF_TC && (event->cid == 0x00 || event->cid == 0x03 || event->cid == 0x04)) + return hid_input_report(ctx->hid, HID_INPUT_REPORT, event->pld, event->len, 1); -+ } + + dev_warn(ctx->dev, "unsupported event (tc = %d, cid = %d)\n", event->tc, event->cid); + return 0; @@ -5182,19 +5162,16 @@ index 000000000000..dc5be3a14a8c + + // add device link to EC + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + drvdata = kzalloc(sizeof(struct sid_vhf_drvdata), GFP_KERNEL); -+ if (!drvdata) { ++ if (!drvdata) + return -ENOMEM; -+ } + + status = vhf_get_metadata(0x00, &meta); -+ if (status) { ++ if (status) + goto err_create_hid; -+ } + + hid = sid_vhf_create_hid_device(pdev, &meta); + if (IS_ERR(hid)) { @@ -5211,19 +5188,16 @@ index 000000000000..dc5be3a14a8c + SAM_EVENT_SID_VHF_RQID, + sid_vhf_event_handler, + &drvdata->event_ctx); -+ if (status) { ++ if (status) + goto err_event_handler; -+ } + + status = surface_sam_ssh_enable_event_source(SAM_EVENT_SID_VHF_TC, 0x01, SAM_EVENT_SID_VHF_RQID); -+ if (status) { ++ if (status) + goto err_event_source; -+ } + + status = hid_add_device(hid); -+ if (status) { ++ if (status) + goto err_add_hid; -+ } + + return 0; + @@ -5269,10 +5243,11 @@ index 000000000000..dc5be3a14a8c +MODULE_ALIAS("platform:surface_sam_sid_vhf"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh.c b/drivers/platform/x86/surface_sam/surface_sam_ssh.c new file mode 100644 -index 000000000000..34905cf29a51 +index 0000000000000..988be7c2d2863 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_ssh.c -@@ -0,0 +1,1773 @@ +@@ -0,0 +1,1744 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* + * Surface Serial Hub (SSH) driver for communication with the Surface/System + * Aggregator Module. @@ -5500,7 +5475,7 @@ index 000000000000..34905cf29a51 +}; + + -+inline static struct sam_ssh_ec *surface_sam_ssh_acquire(void) ++static inline struct sam_ssh_ec *surface_sam_ssh_acquire(void) +{ + struct sam_ssh_ec *ec = &ssh_ec; + @@ -5508,12 +5483,12 @@ index 000000000000..34905cf29a51 + return ec; +} + -+inline static void surface_sam_ssh_release(struct sam_ssh_ec *ec) ++static inline void surface_sam_ssh_release(struct sam_ssh_ec *ec) +{ + mutex_unlock(&ec->lock); +} + -+inline static struct sam_ssh_ec *surface_sam_ssh_acquire_init(void) ++static inline struct sam_ssh_ec *surface_sam_ssh_acquire_init(void) +{ + struct sam_ssh_ec *ec = surface_sam_ssh_acquire(); + @@ -5532,14 +5507,12 @@ index 000000000000..34905cf29a51 + struct device_link *link; + + ec = surface_sam_ssh_acquire_init(); -+ if (!ec) { ++ if (!ec) + return -ENXIO; -+ } + + link = device_link_add(consumer, &ec->serdev->dev, flags); -+ if (!link) { ++ if (!link) + return -EFAULT; -+ } + + surface_sam_ssh_release(ec); + return 0; @@ -5547,12 +5520,15 @@ index 000000000000..34905cf29a51 +EXPORT_SYMBOL_GPL(surface_sam_ssh_consumer_register); + + -+inline static u16 sam_rqid_to_rqst(u16 rqid) { ++static inline u16 sam_rqid_to_rqst(u16 rqid) ++{ + return rqid << SURFACE_SAM_SSH_RQID_EVENT_BITS; +} + -+inline static bool sam_rqid_is_event(u16 rqid) { ++static inline bool sam_rqid_is_event(u16 rqid) ++{ + const u16 mask = (1 << SURFACE_SAM_SSH_RQID_EVENT_BITS) - 1; ++ + return rqid != 0 && (rqid | mask) == mask; +} + @@ -5580,16 +5556,15 @@ index 000000000000..34905cf29a51 + int status; + + // only allow RQIDs that lie within event spectrum -+ if (!sam_rqid_is_event(rqid)) { ++ if (!sam_rqid_is_event(rqid)) + return -EINVAL; -+ } + + status = surface_sam_ssh_rqst(&rqst, &result); + + if (buf[0] != 0x00) { -+ printk(KERN_WARNING SSH_RQST_TAG_FULL -+ "unexpected result while enabling event source: 0x%02x\n", -+ buf[0]); ++ pr_warn(SSH_RQST_TAG_FULL ++ "unexpected result while enabling event source: 0x%02x\n", ++ buf[0]); + } + + return status; @@ -5621,16 +5596,15 @@ index 000000000000..34905cf29a51 + int status; + + // only allow RQIDs that lie within event spectrum -+ if (!sam_rqid_is_event(rqid)) { ++ if (!sam_rqid_is_event(rqid)) + return -EINVAL; -+ } + + status = surface_sam_ssh_rqst(&rqst, &result); + + if (buf[0] != 0x00) { -+ printk(KERN_WARNING SSH_RQST_TAG_FULL -+ "unexpected result while disabling event source: 0x%02x\n", -+ buf[0]); ++ pr_warn(SSH_RQST_TAG_FULL ++ "unexpected result while disabling event source: 0x%02x\n", ++ buf[0]); + } + + return status; @@ -5650,18 +5624,15 @@ index 000000000000..34905cf29a51 + struct sam_ssh_ec *ec; + unsigned long flags; + -+ if (!sam_rqid_is_event(rqid)) { ++ if (!sam_rqid_is_event(rqid)) + return -EINVAL; -+ } + + ec = surface_sam_ssh_acquire_init(); -+ if (!ec) { ++ if (!ec) + return -ENXIO; -+ } + -+ if (!delay) { ++ if (!delay) + delay = sam_event_default_delay; -+ } + + spin_lock_irqsave(&ec->events.lock, flags); + // check if we already have a handler @@ -5687,14 +5658,12 @@ index 000000000000..34905cf29a51 + struct sam_ssh_ec *ec; + unsigned long flags; + -+ if (!sam_rqid_is_event(rqid)) { ++ if (!sam_rqid_is_event(rqid)) + return -EINVAL; -+ } + + ec = surface_sam_ssh_acquire_init(); -+ if (!ec) { ++ if (!ec) + return -ENXIO; -+ } + + spin_lock_irqsave(&ec->events.lock, flags); + @@ -5717,24 +5686,24 @@ index 000000000000..34905cf29a51 +EXPORT_SYMBOL_GPL(surface_sam_ssh_remove_event_handler); + + -+inline static u16 ssh_crc(const u8 *buf, size_t size) ++static inline u16 ssh_crc(const u8 *buf, size_t size) +{ + return crc_ccitt_false(0xffff, buf, size); +} + -+inline static void ssh_write_u16(struct ssh_writer *writer, u16 in) ++static inline void ssh_write_u16(struct ssh_writer *writer, u16 in) +{ + put_unaligned_le16(in, writer->ptr); + writer->ptr += 2; +} + -+inline static void ssh_write_crc(struct ssh_writer *writer, ++static inline void ssh_write_crc(struct ssh_writer *writer, + const u8 *buf, size_t size) +{ + ssh_write_u16(writer, ssh_crc(buf, size)); +} + -+inline static void ssh_write_syn(struct ssh_writer *writer) ++static inline void ssh_write_syn(struct ssh_writer *writer) +{ + u8 *w = writer->ptr; + @@ -5744,7 +5713,7 @@ index 000000000000..34905cf29a51 + writer->ptr = w; +} + -+inline static void ssh_write_ter(struct ssh_writer *writer) ++static inline void ssh_write_ter(struct ssh_writer *writer) +{ + u8 *w = writer->ptr; + @@ -5754,13 +5723,13 @@ index 000000000000..34905cf29a51 + writer->ptr = w; +} + -+inline static void ssh_write_buf(struct ssh_writer *writer, ++static inline void ssh_write_buf(struct ssh_writer *writer, + u8 *in, size_t len) +{ + writer->ptr = memcpy(writer->ptr, in, len) + len; +} + -+inline static void ssh_write_hdr(struct ssh_writer *writer, ++static inline void ssh_write_hdr(struct ssh_writer *writer, + const struct surface_sam_ssh_rqst *rqst, + struct sam_ssh_ec *ec) +{ @@ -5777,7 +5746,7 @@ index 000000000000..34905cf29a51 + ssh_write_crc(writer, begin, writer->ptr - begin); +} + -+inline static void ssh_write_cmd(struct ssh_writer *writer, ++static inline void ssh_write_cmd(struct ssh_writer *writer, + const struct surface_sam_ssh_rqst *rqst, + struct sam_ssh_ec *ec) +{ @@ -5803,7 +5772,7 @@ index 000000000000..34905cf29a51 + ssh_write_crc(writer, begin, writer->ptr - begin); +} + -+inline static void ssh_write_ack(struct ssh_writer *writer, u8 seq) ++static inline void ssh_write_ack(struct ssh_writer *writer, u8 seq) +{ + struct ssh_frame_ctrl *ack = (struct ssh_frame_ctrl *)writer->ptr; + u8 *begin = writer->ptr; @@ -5818,12 +5787,12 @@ index 000000000000..34905cf29a51 + ssh_write_crc(writer, begin, writer->ptr - begin); +} + -+inline static void ssh_writer_reset(struct ssh_writer *writer) ++static inline void ssh_writer_reset(struct ssh_writer *writer) +{ + writer->ptr = writer->data; +} + -+inline static int ssh_writer_flush(struct sam_ssh_ec *ec) ++static inline int ssh_writer_flush(struct sam_ssh_ec *ec) +{ + struct ssh_writer *writer = &ec->writer; + struct serdev_device *serdev = ec->serdev; @@ -5833,13 +5802,13 @@ index 000000000000..34905cf29a51 + + dev_dbg(&ec->serdev->dev, "sending message\n"); + print_hex_dump_debug("send: ", DUMP_PREFIX_OFFSET, 16, 1, -+ writer->data, writer->ptr - writer->data, false); ++ writer->data, writer->ptr - writer->data, false); + + status = serdev_device_write(serdev, writer->data, len, SSH_WRITE_TIMEOUT); + return status >= 0 ? 0 : status; +} + -+inline static void ssh_write_msg_cmd(struct sam_ssh_ec *ec, ++static inline void ssh_write_msg_cmd(struct sam_ssh_ec *ec, + const struct surface_sam_ssh_rqst *rqst) +{ + ssh_writer_reset(&ec->writer); @@ -5848,7 +5817,7 @@ index 000000000000..34905cf29a51 + ssh_write_cmd(&ec->writer, rqst, ec); +} + -+inline static void ssh_write_msg_ack(struct sam_ssh_ec *ec, u8 seq) ++static inline void ssh_write_msg_ack(struct sam_ssh_ec *ec, u8 seq) +{ + ssh_writer_reset(&ec->writer); + ssh_write_syn(&ec->writer); @@ -5856,7 +5825,7 @@ index 000000000000..34905cf29a51 + ssh_write_ter(&ec->writer); +} + -+inline static void ssh_receiver_restart(struct sam_ssh_ec *ec, ++static inline void ssh_receiver_restart(struct sam_ssh_ec *ec, + const struct surface_sam_ssh_rqst *rqst) +{ + unsigned long flags; @@ -5871,7 +5840,7 @@ index 000000000000..34905cf29a51 + spin_unlock_irqrestore(&ec->receiver.lock, flags); +} + -+inline static void ssh_receiver_discard(struct sam_ssh_ec *ec) ++static inline void ssh_receiver_discard(struct sam_ssh_ec *ec) +{ + unsigned long flags; + @@ -5904,18 +5873,16 @@ index 000000000000..34905cf29a51 + // send command, try to get an ack response + for (try = 0; try < SSH_NUM_RETRY; try++) { + status = ssh_writer_flush(ec); -+ if (status) { ++ if (status) + goto out; -+ } + + rem = wait_for_completion_timeout(&ec->receiver.signal, SSH_READ_TIMEOUT); + if (rem) { + // completion assures valid packet, thus ignore returned length + (void) !kfifo_out(&ec->receiver.fifo, &packet, sizeof(packet)); + -+ if (packet.type == SSH_FRAME_TYPE_ACK) { ++ if (packet.type == SSH_FRAME_TYPE_ACK) + break; -+ } + } + } + @@ -5954,9 +5921,8 @@ index 000000000000..34905cf29a51 + if (packet.type == SSH_FRAME_TYPE_CMD) { + ssh_write_msg_ack(ec, packet.seq); + status = ssh_writer_flush(ec); -+ if (status) { ++ if (status) + goto out; -+ } + } + } + @@ -5972,7 +5938,7 @@ index 000000000000..34905cf29a51 + + ec = surface_sam_ssh_acquire_init(); + if (!ec) { -+ printk(KERN_WARNING SSH_RQST_TAG_FULL "embedded controller is uninitialized\n"); ++ pr_warn(SSH_RQST_TAG_FULL "embedded controller is uninitialized\n"); + return -ENXIO; + } + @@ -6011,14 +5977,15 @@ index 000000000000..34905cf29a51 + result.data = buf, + }; + -+ int status = surface_sam_ssh_rqst_unlocked(ec, &rqst, &result); -+ if (status) { ++ int status; ++ ++ status = surface_sam_ssh_rqst_unlocked(ec, &rqst, &result); ++ if (status) + return status; -+ } + + if (buf[0] != 0x00) { + dev_warn(&ec->serdev->dev, -+ "unexpected result while trying to resume EC: 0x%02x\n", ++ "unexpected result while trying to resume EC: 0x%02x\n", + buf[0]); + } + @@ -6045,14 +6012,15 @@ index 000000000000..34905cf29a51 + result.data = buf, + }; + -+ int status = surface_sam_ssh_rqst_unlocked(ec, &rqst, &result); -+ if (status) { ++ int status; ++ ++ status = surface_sam_ssh_rqst_unlocked(ec, &rqst, &result); ++ if (status) + return status; -+ } + + if (buf[0] != 0x00) { + dev_warn(&ec->serdev->dev, -+ "unexpected result while trying to suspend EC: 0x%02x\n", ++ "unexpected result while trying to suspend EC: 0x%02x\n", + buf[0]); + } + @@ -6060,19 +6028,21 @@ index 000000000000..34905cf29a51 +} + + -+inline static bool ssh_is_valid_syn(const u8 *ptr) ++static inline bool ssh_is_valid_syn(const u8 *ptr) +{ + return ptr[0] == 0xaa && ptr[1] == 0x55; +} + -+inline static bool ssh_is_valid_ter(const u8 *ptr) ++static inline bool ssh_is_valid_ter(const u8 *ptr) +{ + return ptr[0] == 0xff && ptr[1] == 0xff; +} + -+inline static bool ssh_is_valid_crc(const u8 *begin, const u8 *end) ++static inline bool ssh_is_valid_crc(const u8 *begin, const u8 *end) +{ -+ u16 crc = ssh_crc(begin, end - begin); ++ u16 crc; ++ ++ crc = ssh_crc(begin, end - begin); + return (end[0] == (crc & 0xff)) && (end[1] == (crc >> 8)); +} + @@ -6099,7 +6069,7 @@ index 000000000000..34905cf29a51 + + dev_dbg(&ec->serdev->dev, "sending message\n"); + print_hex_dump_debug("send: ", DUMP_PREFIX_OFFSET, 16, 1, -+ buf, SSH_MSG_LEN_CTRL, false); ++ buf, SSH_MSG_LEN_CTRL, false); + + status = serdev_device_write(ec->serdev, buf, SSH_MSG_LEN_CTRL, SSH_WRITE_TIMEOUT); + return status >= 0 ? 0 : status; @@ -6118,19 +6088,17 @@ index 000000000000..34905cf29a51 + ec = work->ec; + dev = &ec->serdev->dev; + -+ // make sure we load a fresh ec state ++ /* make sure we load a fresh ec state */ + smp_mb(); + + if (ec->state == SSH_EC_INITIALIZED) { + status = surface_sam_ssh_send_ack(ec, work->seq); -+ if (status) { ++ if (status) + dev_err(dev, SSH_EVENT_TAG "failed to send ACK: %d\n", status); -+ } + } + -+ if (refcount_dec_and_test(&work->refcount)) { ++ if (refcount_dec_and_test(&work->refcount)) + kfree(work); -+ } +} + +static void surface_sam_ssh_event_work_evt_handler(struct work_struct *_work) @@ -6163,24 +6131,20 @@ index 000000000000..34905cf29a51 + * guaranteed to be valid at least until this function returns. + */ + -+ if (handler) { ++ if (handler) + status = handler(event, handler_data); -+ } else { ++ else + dev_warn(dev, SSH_EVENT_TAG "unhandled event (rqid: %04x)\n", event->rqid); -+ } + -+ if (status) { ++ if (status) + dev_err(dev, SSH_EVENT_TAG "error handling event: %d\n", status); -+ } + -+ if (refcount_dec_and_test(&work->refcount)) { ++ if (refcount_dec_and_test(&work->refcount)) + kfree(work); -+ } +} + +static void ssh_handle_event(struct sam_ssh_ec *ec, const u8 *buf) +{ -+ struct device *dev = &ec->serdev->dev; + const struct ssh_frame_ctrl *ctrl; + const struct ssh_frame_cmd *cmd; + struct ssh_event_work *work; @@ -6197,10 +6161,8 @@ index 000000000000..34905cf29a51 + pld_len = ctrl->len - SSH_BYTELEN_CMDFRAME; + + work = kzalloc(sizeof(struct ssh_event_work) + pld_len, GFP_ATOMIC); -+ if (!work) { -+ dev_warn(dev, SSH_EVENT_TAG "failed to allocate memory, dropping event\n"); ++ if (!work) + return; -+ } + + refcount_set(&work->refcount, 1); + work->ec = ec; @@ -6211,7 +6173,7 @@ index 000000000000..34905cf29a51 + work->event.iid = cmd->iid; + work->event.pri = cmd->pri_in; + work->event.len = pld_len; -+ work->event.pld = ((u8*) work) + sizeof(struct ssh_event_work); ++ work->event.pld = ((u8 *)work) + sizeof(struct ssh_event_work); + + memcpy(work->event.pld, buf + SSH_FRAME_OFFS_CMD_PLD, pld_len); + @@ -6255,9 +6217,8 @@ index 000000000000..34905cf29a51 + ctrl = (const struct ssh_frame_ctrl *)(ctrl_begin); + + // actual length check -+ if (size < SSH_MSG_LEN_CTRL) { ++ if (size < SSH_MSG_LEN_CTRL) + return 0; // need more bytes -+ } + + // validate TERM + if (!ssh_is_valid_ter(buf + SSH_FRAME_OFFS_TERM)) { @@ -6332,9 +6293,8 @@ index 000000000000..34905cf29a51 + cmd = (const struct ssh_frame_cmd *)(cmd_begin); + + // we need at least a full control frame -+ if (size < (SSH_BYTELEN_SYNC + SSH_BYTELEN_CTRL + SSH_BYTELEN_CRC)) { ++ if (size < (SSH_BYTELEN_SYNC + SSH_BYTELEN_CTRL + SSH_BYTELEN_CRC)) + return 0; // need more bytes -+ } + + // validate control-frame CRC + if (!ssh_is_valid_crc(ctrl_begin, ctrl_end)) { @@ -6348,9 +6308,8 @@ index 000000000000..34905cf29a51 + + // actual length check (ctrl->len contains command-frame but not crc) + msg_len = SSH_MSG_LEN_CMD_BASE + ctrl->len; -+ if (size < msg_len) { ++ if (size < msg_len) + return 0; // need more bytes -+ } + + cmd_end = cmd_begin + ctrl->len; + @@ -6421,9 +6380,8 @@ index 000000000000..34905cf29a51 + struct ssh_frame_ctrl *ctrl; + + // we need at least a control frame to check what to do -+ if (size < (SSH_BYTELEN_SYNC + SSH_BYTELEN_CTRL)) { ++ if (size < (SSH_BYTELEN_SYNC + SSH_BYTELEN_CTRL)) + return 0; // need more bytes -+ } + + // make sure we're actually at the start of a new message + if (!ssh_is_valid_syn(buf)) { @@ -6431,7 +6389,7 @@ index 000000000000..34905cf29a51 + return size; // discard everything + } + -+ // handle individual message types seperately ++ // handle individual message types separately + ctrl = (struct ssh_frame_ctrl *)(buf + SSH_FRAME_OFFS_CTRL); + + switch (ctrl->type) { @@ -6477,7 +6435,8 @@ index 000000000000..34905cf29a51 + while (offs < rcv->eval_buf.len) { + n = rcv->eval_buf.len - offs; + n = ssh_eval_buf(ec, rcv->eval_buf.ptr + offs, n); -+ if (n <= 0) break; // need more bytes ++ if (n <= 0) ++ break; // need more bytes + + offs += n; + } @@ -6511,11 +6470,10 @@ index 000000000000..34905cf29a51 +} __packed; + +static ssize_t rqst_read(struct file *f, struct kobject *kobj, struct bin_attribute *attr, -+ char *buf, loff_t offs, size_t count) ++ char *buf, loff_t offs, size_t count) +{ -+ if (offs < 0 || count + offs > SURFACE_SAM_SSH_MAX_RQST_RESPONSE) { ++ if (offs < 0 || count + offs > SURFACE_SAM_SSH_MAX_RQST_RESPONSE) + return -EINVAL; -+ } + + memcpy(buf, sam_ssh_debug_rqst_buf_sysfs + offs, count); + return count; @@ -6530,20 +6488,17 @@ index 000000000000..34905cf29a51 + int status; + + // check basic write constriants -+ if (offs != 0 || count > SURFACE_SAM_SSH_MAX_RQST_PAYLOAD + sizeof(struct sysfs_rqst)) { ++ if (offs != 0 || count > SURFACE_SAM_SSH_MAX_RQST_PAYLOAD + sizeof(struct sysfs_rqst)) + return -EINVAL; -+ } + -+ if (count < sizeof(struct sysfs_rqst)) { ++ if (count < sizeof(struct sysfs_rqst)) + return -EINVAL; -+ } + + input = (struct sysfs_rqst *)buf; + + // payload length should be consistent with data provided -+ if (input->cdl + sizeof(struct sysfs_rqst) != count) { ++ if (input->cdl + sizeof(struct sysfs_rqst) != count) + return -EINVAL; -+ } + + rqst.tc = input->tc; + rqst.cid = input->cid; @@ -6559,9 +6514,8 @@ index 000000000000..34905cf29a51 + result.data = sam_ssh_debug_rqst_buf_res; + + status = surface_sam_ssh_rqst(&rqst, &result); -+ if (status) { ++ if (status) + return status; -+ } + + sam_ssh_debug_rqst_buf_sysfs[0] = result.len; + memcpy(sam_ssh_debug_rqst_buf_sysfs + 1, result.data, result.len); @@ -6574,24 +6528,24 @@ index 000000000000..34905cf29a51 +static const BIN_ATTR_RW(rqst, SURFACE_SAM_SSH_MAX_RQST_RESPONSE + 1); + + -+int surface_sam_ssh_sysfs_register(struct device *dev) ++static int surface_sam_ssh_sysfs_register(struct device *dev) +{ + return sysfs_create_bin_file(&dev->kobj, &bin_attr_rqst); +} + -+void surface_sam_ssh_sysfs_unregister(struct device *dev) ++static void surface_sam_ssh_sysfs_unregister(struct device *dev) +{ + sysfs_remove_bin_file(&dev->kobj, &bin_attr_rqst); +} + +#else /* CONFIG_SURFACE_ACPI_SSH_DEBUG_DEVICE */ + -+int surface_sam_ssh_sysfs_register(struct device *dev) ++static int surface_sam_ssh_sysfs_register(struct device *dev) +{ + return 0; +} + -+void surface_sam_ssh_sysfs_unregister(struct device *dev) ++static void surface_sam_ssh_sysfs_unregister(struct device *dev) +{ +} + @@ -6649,14 +6603,12 @@ index 000000000000..34905cf29a51 + struct acpi_resource_uart_serialbus *uart; + int status = 0; + -+ if (resource->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { ++ if (resource->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return AE_OK; -+ } + + serial = &resource->data.common_serial_bus; -+ if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART) { ++ if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART) + return AE_OK; -+ } + + uart = &resource->data.uart_serial_bus; + @@ -6664,9 +6616,8 @@ index 000000000000..34905cf29a51 + serdev_device_set_baudrate(serdev, uart->default_baud_rate); + + // serdev currently only supports RTSCTS flow control -+ if (uart->flow_control & SSH_SUPPORTED_FLOW_CONTROL_MASK) { ++ if (uart->flow_control & SSH_SUPPORTED_FLOW_CONTROL_MASK) + dev_warn(&serdev->dev, "unsupported flow control (value: 0x%02x)\n", uart->flow_control); -+ } + + // set RTSCTS flow control + serdev_device_set_flow_control(serdev, uart->flow_control & ACPI_UART_FLOW_CONTROL_HW); @@ -6772,8 +6723,8 @@ index 000000000000..34905cf29a51 +}; + + -+int surface_sam_ssh_sysfs_register(struct device *dev); -+void surface_sam_ssh_sysfs_unregister(struct device *dev); ++static int surface_sam_ssh_sysfs_register(struct device *dev); ++static void surface_sam_ssh_sysfs_unregister(struct device *dev); + +static int surface_sam_ssh_probe(struct serdev_device *serdev) +{ @@ -6863,30 +6814,26 @@ index 000000000000..34905cf29a51 + + serdev_device_set_drvdata(serdev, ec); + -+ // ensure everything is properly set-up before we open the device ++ /* ensure everything is properly set-up before we open the device */ + smp_mb(); + + serdev_device_set_client_ops(serdev, &ssh_device_ops); + status = serdev_device_open(serdev); -+ if (status) { ++ if (status) + goto err_open; -+ } + + status = acpi_walk_resources(ssh, METHOD_NAME__CRS, -+ ssh_setup_from_resource, serdev); -+ if (ACPI_FAILURE(status)) { ++ ssh_setup_from_resource, serdev); ++ if (ACPI_FAILURE(status)) + goto err_devinit; -+ } + + status = surface_sam_ssh_ec_resume(ec); -+ if (status) { ++ if (status) + goto err_devinit; -+ } + + status = surface_sam_ssh_sysfs_register(&serdev->dev); -+ if (status) { ++ if (status) + goto err_devinit; -+ } + + surface_sam_ssh_release(ec); + @@ -6932,18 +6879,16 @@ index 000000000000..34905cf29a51 + int status; + + ec = surface_sam_ssh_acquire_init(); -+ if (!ec) { ++ if (!ec) + return; -+ } + + free_irq(ec->irq, serdev); + surface_sam_ssh_sysfs_unregister(&serdev->dev); + + // suspend EC and disable events + status = surface_sam_ssh_ec_suspend(ec); -+ if (status) { ++ if (status) + dev_err(&serdev->dev, "failed to suspend EC: %d\n", status); -+ } + + // make sure all events (received up to now) have been properly handled + flush_workqueue(ec->events.queue_ack); @@ -6953,14 +6898,14 @@ index 000000000000..34905cf29a51 + spin_lock_irqsave(&ec->events.lock, flags); + memset(ec->events.handler, 0, + sizeof(struct ssh_event_handler) -+ * SAM_NUM_EVENT_TYPES); ++ * SAM_NUM_EVENT_TYPES); + spin_unlock_irqrestore(&ec->events.lock, flags); + + // set device to deinitialized state + ec->state = SSH_EC_UNINITIALIZED; + ec->serdev = NULL; + -+ // ensure state and serdev get set before continuing ++ /* ensure state and serdev get set before continuing */ + smp_mb(); + + /* @@ -6973,9 +6918,9 @@ index 000000000000..34905cf29a51 + serdev_device_close(serdev); + + /* -+ * Only at this point, no new events can be received. Destroying the -+ * workqueue here flushes all remaining events. Those events will be -+ * silently ignored and neither ACKed nor any handler gets called. ++ * Only at this point, no new events can be received. Destroying the ++ * workqueue here flushes all remaining events. Those events will be ++ * silently ignored and neither ACKed nor any handler gets called. + */ + destroy_workqueue(ec->events.queue_ack); + destroy_workqueue(ec->events.queue_evt); @@ -7048,10 +6993,11 @@ index 000000000000..34905cf29a51 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/x86/surface_sam/surface_sam_ssh.h b/drivers/platform/x86/surface_sam/surface_sam_ssh.h new file mode 100644 -index 000000000000..714bba6a9457 +index 0000000000000..435b5c7bac9a2 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_ssh.h -@@ -0,0 +1,97 @@ +@@ -0,0 +1,98 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Interface for Surface Serial Hub (SSH). + * @@ -7111,7 +7057,7 @@ index 000000000000..714bba6a9457 + u8 iid; // instance ID + u8 pri; // priority + u8 snc; // expect response flag -+ u8 cdl; // command data length (lenght of payload) ++ u8 cdl; // command data length (length of payload) + u8 *pld; // pointer to payload of length cdl +}; + @@ -7151,12 +7097,13 @@ index 000000000000..714bba6a9457 +#endif /* _SURFACE_SAM_SSH_H */ diff --git a/drivers/platform/x86/surface_sam/surface_sam_vhf.c b/drivers/platform/x86/surface_sam/surface_sam_vhf.c new file mode 100644 -index 000000000000..0ed0ebbdb3cb +index 0000000000000..a00763805eca3 --- /dev/null +++ b/drivers/platform/x86/surface_sam/surface_sam_vhf.c -@@ -0,0 +1,276 @@ +@@ -0,0 +1,270 @@ ++// SPDX-License-Identifier: GPL-2.0 +/* -+ * Virtual HID Framwork (VHF) driver for input events via SAM. ++ * Virtual HID Framework (VHF) driver for input events via SAM. + * Used for keyboard input events on the Surface Laptops. + */ + @@ -7309,9 +7256,8 @@ index 000000000000..0ed0ebbdb3cb + struct hid_device *hid; + + hid = hid_allocate_device(); -+ if (IS_ERR(hid)) { ++ if (IS_ERR(hid)) + return hid; -+ } + + hid->dev.parent = &pdev->dev; + @@ -7330,9 +7276,8 @@ index 000000000000..0ed0ebbdb3cb +{ + struct vhf_evtctx *ctx = (struct vhf_evtctx *)data; + -+ if (event->tc == 0x08 && (event->cid == 0x03 || event->cid == 0x04)) { ++ if (event->tc == 0x08 && (event->cid == 0x03 || event->cid == 0x04)) + return hid_input_report(ctx->hid, HID_INPUT_REPORT, event->pld, event->len, 1); -+ } + + dev_warn(ctx->dev, "unsupported event (tc = %d, cid = %d)\n", event->tc, event->cid); + return 0; @@ -7346,14 +7291,12 @@ index 000000000000..0ed0ebbdb3cb + + // add device link to EC + status = surface_sam_ssh_consumer_register(&pdev->dev); -+ if (status) { ++ if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; -+ } + + drvdata = kzalloc(sizeof(struct vhf_drvdata), GFP_KERNEL); -+ if (!drvdata) { ++ if (!drvdata) + return -ENOMEM; -+ } + + hid = vhf_create_hid_device(pdev); + if (IS_ERR(hid)) { @@ -7362,9 +7305,8 @@ index 000000000000..0ed0ebbdb3cb + } + + status = hid_add_device(hid); -+ if (status) { ++ if (status) + goto err_add_hid; -+ } + + drvdata->event_ctx.dev = &pdev->dev; + drvdata->event_ctx.hid = hid; @@ -7373,16 +7315,14 @@ index 000000000000..0ed0ebbdb3cb + + status = surface_sam_ssh_set_event_handler( + SAM_EVENT_VHF_RQID, -+ vhf_event_handler, ++ vhf_event_handler, + &drvdata->event_ctx); -+ if (status) { ++ if (status) + goto err_add_hid; -+ } + + status = surface_sam_ssh_enable_event_source(SAM_EVENT_VHF_TC, 0x01, SAM_EVENT_VHF_RQID); -+ if (status) { ++ if (status) + goto err_event_source; -+ } + + return 0; + @@ -7432,7 +7372,7 @@ index 000000000000..0ed0ebbdb3cb +MODULE_DESCRIPTION("Virtual HID Framework Driver for 5th Generation Surface Devices"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c -index a9719858c950..ce5309d00280 100644 +index a9719858c950b..ce5309d002805 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -552,16 +552,97 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) @@ -7587,5 +7527,5 @@ index a9719858c950..ce5309d00280 100644 if (!ctrl->serdev) return -ENODEV; -- -2.25.0 +2.26.2 diff --git a/patches/5.4/0006-surface-lte.patch b/patches/5.4/0005-surface-lte.patch similarity index 76% rename from patches/5.4/0006-surface-lte.patch rename to patches/5.4/0005-surface-lte.patch index 258517874..6007c864b 100644 --- a/patches/5.4/0006-surface-lte.patch +++ b/patches/5.4/0005-surface-lte.patch @@ -1,17 +1,17 @@ -From 459807ca9074d2ffba9ae7754e4c66a0679c6c70 Mon Sep 17 00:00:00 2001 +From d1452bffe608f437cb7a9db6b7223acf2ad4c87b Mon Sep 17 00:00:00 2001 From: qzed Date: Tue, 17 Sep 2019 17:21:43 +0200 -Subject: [PATCH 6/7] surface-lte +Subject: [PATCH 5/7] surface-lte --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c -index 613f91add03d..e1428222dd73 100644 +index ce0401d3137f1..b0c190cd46c92 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c -@@ -177,6 +177,7 @@ static const struct usb_device_id id_table[] = { +@@ -178,6 +178,7 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x413c, 0x81d0)}, /* Dell Wireless 5819 */ {DEVICE_SWI(0x413c, 0x81d1)}, /* Dell Wireless 5818 */ {DEVICE_SWI(0x413c, 0x81d2)}, /* Dell Wireless 5818 */ @@ -20,5 +20,5 @@ index 613f91add03d..e1428222dd73 100644 /* Huawei devices */ {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */ -- -2.25.0 +2.26.2 diff --git a/patches/5.4/0006-wifi.patch b/patches/5.4/0006-wifi.patch new file mode 100644 index 000000000..62e720ed7 --- /dev/null +++ b/patches/5.4/0006-wifi.patch @@ -0,0 +1,255 @@ +From 503e9e13d52372e50e52438cdf7d3c7113edb771 Mon Sep 17 00:00:00 2001 +From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> +Date: Thu, 20 Feb 2020 16:51:11 +0900 +Subject: [PATCH 6/7] wifi + +--- + .../net/wireless/marvell/mwifiex/cfg80211.c | 26 ++++++ + drivers/net/wireless/marvell/mwifiex/pcie.c | 84 +++++++++++-------- + .../net/wireless/marvell/mwifiex/sta_cmd.c | 31 ++----- + 3 files changed, 84 insertions(+), 57 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +index d896841685008..108d7ac6a0dd9 100644 +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -25,6 +25,11 @@ + static char *reg_alpha2; + module_param(reg_alpha2, charp, 0); + ++static bool allow_ps_mode; ++module_param(allow_ps_mode, bool, 0444); ++MODULE_PARM_DESC(allow_ps_mode, ++ "allow WiFi power management to be enabled. (default: disallowed)"); ++ + static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { + { + .max = 3, .types = BIT(NL80211_IFTYPE_STATION) | +@@ -439,6 +444,27 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + + ps_mode = enabled; + ++ /* Allow ps_mode to be enabled only when allow_ps_mode is set ++ * (but always allow ps_mode to be disabled in case it gets enabled ++ * for unknown reason and you want to disable it) */ ++ if (ps_mode && !allow_ps_mode) { ++ dev_info(priv->adapter->dev, ++ "Request to enable ps_mode received but it's disallowed " ++ "by module parameter. Rejecting the request.\n"); ++ ++ /* Return negative value to inform userspace tools that setting ++ * power_save to be enabled is not permitted. */ ++ return -1; ++ } ++ ++ if (ps_mode) ++ dev_warn(priv->adapter->dev, ++ "WARN: Request to enable ps_mode received. Enabling it. " ++ "Disable it if you encounter connection instability.\n"); ++ else ++ dev_info(priv->adapter->dev, ++ "Request to disable ps_mode received. Disabling it.\n"); ++ + return mwifiex_drv_set_power(priv, &ps_mode); + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index fc1706d0647d7..b51c5e3571426 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -146,38 +146,45 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) + * + * If already not suspended, this function allocates and sends a host + * sleep activate request to the firmware and turns off the traffic. ++ * ++ * XXX: ignoring all the above comment and just removes the card to ++ * fix S0ix and "AP scanning (sometimes) not working after suspend". ++ * Required code is extracted from mwifiex_pcie_remove(). + */ + static int mwifiex_pcie_suspend(struct device *dev) + { ++ struct pci_dev *pdev = to_pci_dev(dev); ++ struct pcie_service_card *card = pci_get_drvdata(pdev); + struct mwifiex_adapter *adapter; +- struct pcie_service_card *card = dev_get_drvdata(dev); +- ++ struct mwifiex_private *priv; ++ const struct mwifiex_pcie_card_reg *reg; ++ u32 fw_status; ++ int ret; + + /* Might still be loading firmware */ + wait_for_completion(&card->fw_done); + + adapter = card->adapter; +- if (!adapter) { +- dev_err(dev, "adapter is not valid\n"); ++ if (!adapter || !adapter->priv_num) + return 0; +- } + +- mwifiex_enable_wake(adapter); ++ reg = card->pcie.reg; ++ if (reg) ++ ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status); ++ else ++ fw_status = -1; + +- /* Enable the Host Sleep */ +- if (!mwifiex_enable_hs(adapter)) { +- mwifiex_dbg(adapter, ERROR, +- "cmd: failed to suspend\n"); +- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); +- mwifiex_disable_wake(adapter); +- return -EFAULT; +- } ++ if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) { ++ mwifiex_deauthenticate_all(adapter); + +- flush_workqueue(adapter->workqueue); ++ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); ++ ++ mwifiex_disable_auto_ds(priv); + +- /* Indicate device suspended */ +- set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); +- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); ++ mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); ++ } ++ ++ mwifiex_remove_card(adapter); + + return 0; + } +@@ -189,31 +196,35 @@ static int mwifiex_pcie_suspend(struct device *dev) + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. ++ * ++ * XXX: ignoring all the above comment and probes the card that was ++ * removed on suspend. Required code is extracted from mwifiex_pcie_probe(). + */ + static int mwifiex_pcie_resume(struct device *dev) + { +- struct mwifiex_adapter *adapter; +- struct pcie_service_card *card = dev_get_drvdata(dev); ++ struct pci_dev *pdev = to_pci_dev(dev); ++ struct pcie_service_card *card = pci_get_drvdata(pdev); ++ int ret; + ++ pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", ++ pdev->vendor, pdev->device, pdev->revision); + +- if (!card->adapter) { +- dev_err(dev, "adapter structure is not valid\n"); +- return 0; +- } ++ init_completion(&card->fw_done); + +- adapter = card->adapter; ++ card->dev = pdev; + +- if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { +- mwifiex_dbg(adapter, WARN, +- "Device already resumed\n"); +- return 0; ++ /* device tree node parsing and platform specific configuration */ ++ if (pdev->dev.of_node) { ++ ret = mwifiex_pcie_probe_of(&pdev->dev); ++ if (ret) ++ return ret; + } + +- clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); +- +- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), +- MWIFIEX_ASYNC_CMD); +- mwifiex_disable_wake(adapter); ++ if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, ++ MWIFIEX_PCIE, &pdev->dev)) { ++ pr_err("%s failed\n", __func__); ++ return -1; ++ } + + return 0; + } +@@ -229,8 +240,13 @@ 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; + ++ /* disable bridge_d3 to fix driver crashing after suspend on gen4+ ++ * Surface devices */ ++ parent_pdev->bridge_d3 = false; ++ + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", + pdev->vendor, pdev->device, pdev->revision); + +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +index 4ed10cf82f9a4..410bef3d6a6eb 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +@@ -2254,7 +2254,6 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + * - Function init (for first interface only) + * - Read MAC address (for first interface only) + * - Reconfigure Tx buffer size (for first interface only) +- * - Enable auto deep sleep (for first interface only) + * - Get Tx rate + * - Get Tx power + * - Set IBSS coalescing status +@@ -2267,7 +2266,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + struct mwifiex_adapter *adapter = priv->adapter; + int ret; + struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; +- struct mwifiex_ds_auto_ds auto_ds; + enum state_11d_t state_11d; + struct mwifiex_ds_11n_tx_cfg tx_cfg; + u8 sdio_sp_rx_aggr_enable; +@@ -2339,16 +2337,10 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + if (ret) + return -1; + +- if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { +- /* Enable IEEE PS by default */ +- priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; +- ret = mwifiex_send_cmd(priv, +- HostCmd_CMD_802_11_PS_MODE_ENH, +- EN_AUTO_PS, BITMAP_STA_PS, NULL, +- true); +- if (ret) +- return -1; +- } ++ /* Not enabling ps_mode (IEEE power_save) by default. Enabling ++ * this causes connection instability, especially on 5GHz APs ++ * and eventually causes "firmware wakeup failed". Therefore, ++ * the relevant code was removed from here. */ + + if (drcs) { + adapter->drcs_enabled = true; +@@ -2395,17 +2387,10 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + if (ret) + return -1; + +- if (!disable_auto_ds && first_sta && +- priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { +- /* Enable auto deep sleep */ +- auto_ds.auto_ds = DEEP_SLEEP_ON; +- auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; +- ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, +- EN_AUTO_PS, BITMAP_AUTO_DS, +- &auto_ds, true); +- if (ret) +- return -1; +- } ++ /* Not enabling auto deep sleep (auto_ds) by default. Enabling ++ * this reportedly causes "suspend/resume fails when not connected ++ * to an Access Point." Therefore, the relevant code was removed ++ * from here. */ + + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + /* Send cmd to FW to enable/disable 11D function */ +-- +2.26.2 + diff --git a/patches/5.4/0007-ipts.patch b/patches/5.4/0007-ipts.patch new file mode 100644 index 000000000..60c3e45b3 --- /dev/null +++ b/patches/5.4/0007-ipts.patch @@ -0,0 +1,2061 @@ +From 08f34dc84753960c03b6d4a7838752d890ef2b3b Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Mon, 27 Jan 2020 21:16:20 +0100 +Subject: [PATCH 7/7] ipts + +--- + drivers/input/touchscreen/Kconfig | 2 + + drivers/input/touchscreen/Makefile | 1 + + drivers/input/touchscreen/ipts/Kconfig | 16 ++ + drivers/input/touchscreen/ipts/Makefile | 17 ++ + drivers/input/touchscreen/ipts/context.h | 60 ++++ + drivers/input/touchscreen/ipts/control.c | 94 +++++++ + drivers/input/touchscreen/ipts/control.h | 18 ++ + drivers/input/touchscreen/ipts/data.c | 107 +++++++ + drivers/input/touchscreen/ipts/data.h | 12 + + drivers/input/touchscreen/ipts/hid.c | 38 +++ + drivers/input/touchscreen/ipts/hid.h | 13 + + drivers/input/touchscreen/ipts/init.c | 93 ++++++ + drivers/input/touchscreen/ipts/math.c | 103 +++++++ + drivers/input/touchscreen/ipts/math.h | 21 ++ + drivers/input/touchscreen/ipts/params.c | 27 ++ + drivers/input/touchscreen/ipts/params.h | 15 + + drivers/input/touchscreen/ipts/payload.c | 52 ++++ + drivers/input/touchscreen/ipts/payload.h | 14 + + .../touchscreen/ipts/protocol/commands.h | 61 ++++ + .../input/touchscreen/ipts/protocol/data.h | 30 ++ + .../input/touchscreen/ipts/protocol/events.h | 29 ++ + .../touchscreen/ipts/protocol/feedback.h | 30 ++ + .../input/touchscreen/ipts/protocol/payload.h | 47 ++++ + .../touchscreen/ipts/protocol/responses.h | 62 ++++ + .../touchscreen/ipts/protocol/singletouch.h | 17 ++ + .../input/touchscreen/ipts/protocol/stylus.h | 52 ++++ + drivers/input/touchscreen/ipts/receiver.c | 265 ++++++++++++++++++ + drivers/input/touchscreen/ipts/receiver.h | 8 + + drivers/input/touchscreen/ipts/resources.c | 131 +++++++++ + drivers/input/touchscreen/ipts/resources.h | 11 + + drivers/input/touchscreen/ipts/singletouch.c | 64 +++++ + drivers/input/touchscreen/ipts/singletouch.h | 14 + + drivers/input/touchscreen/ipts/stylus.c | 179 ++++++++++++ + drivers/input/touchscreen/ipts/stylus.h | 14 + + drivers/misc/mei/hw-me-regs.h | 2 + + drivers/misc/mei/pci-me.c | 2 + + include/uapi/linux/input.h | 1 + + 37 files changed, 1722 insertions(+) + create mode 100644 drivers/input/touchscreen/ipts/Kconfig + create mode 100644 drivers/input/touchscreen/ipts/Makefile + create mode 100644 drivers/input/touchscreen/ipts/context.h + create mode 100644 drivers/input/touchscreen/ipts/control.c + create mode 100644 drivers/input/touchscreen/ipts/control.h + create mode 100644 drivers/input/touchscreen/ipts/data.c + create mode 100644 drivers/input/touchscreen/ipts/data.h + create mode 100644 drivers/input/touchscreen/ipts/hid.c + create mode 100644 drivers/input/touchscreen/ipts/hid.h + create mode 100644 drivers/input/touchscreen/ipts/init.c + create mode 100644 drivers/input/touchscreen/ipts/math.c + create mode 100644 drivers/input/touchscreen/ipts/math.h + create mode 100644 drivers/input/touchscreen/ipts/params.c + create mode 100644 drivers/input/touchscreen/ipts/params.h + create mode 100644 drivers/input/touchscreen/ipts/payload.c + create mode 100644 drivers/input/touchscreen/ipts/payload.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/commands.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/data.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/events.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/feedback.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/payload.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/responses.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/singletouch.h + create mode 100644 drivers/input/touchscreen/ipts/protocol/stylus.h + create mode 100644 drivers/input/touchscreen/ipts/receiver.c + create mode 100644 drivers/input/touchscreen/ipts/receiver.h + create mode 100644 drivers/input/touchscreen/ipts/resources.c + create mode 100644 drivers/input/touchscreen/ipts/resources.h + create mode 100644 drivers/input/touchscreen/ipts/singletouch.c + create mode 100644 drivers/input/touchscreen/ipts/singletouch.h + create mode 100644 drivers/input/touchscreen/ipts/stylus.c + create mode 100644 drivers/input/touchscreen/ipts/stylus.h + +diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig +index 46ad9090493bb..c476a153b2f80 100644 +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -1314,4 +1314,6 @@ config TOUCHSCREEN_IQS5XX + To compile this driver as a module, choose M here: the + module will be called iqs5xx. + ++source "drivers/input/touchscreen/ipts/Kconfig" ++ + endif +diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile +index 94c6162409b37..864f0e092ab67 100644 +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o + obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o ++obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts/ + obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o + obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o + obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o +diff --git a/drivers/input/touchscreen/ipts/Kconfig b/drivers/input/touchscreen/ipts/Kconfig +new file mode 100644 +index 0000000000000..d3c530dafa948 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/Kconfig +@@ -0,0 +1,16 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++ ++config TOUCHSCREEN_IPTS ++ tristate "Intel Precise Touch & Stylus" ++ select INTEL_MEI ++ depends on X86 ++ depends on PCI ++ depends on HID ++ help ++ Say Y here if your system has a touchscreen using Intels ++ Precise Touch & Stylus (IPTS). ++ ++ If unsure say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called ipts. +diff --git a/drivers/input/touchscreen/ipts/Makefile b/drivers/input/touchscreen/ipts/Makefile +new file mode 100644 +index 0000000000000..0f7c904e73171 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/Makefile +@@ -0,0 +1,17 @@ ++# SPDX-License-Identifier: GPL-2.0-or-later ++# ++# Makefile for the IPTS touchscreen driver ++# ++ ++obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts.o ++ipts-objs := control.o ++ipts-objs += data.o ++ipts-objs += hid.o ++ipts-objs += init.o ++ipts-objs += math.o ++ipts-objs += params.o ++ipts-objs += payload.o ++ipts-objs += receiver.o ++ipts-objs += resources.o ++ipts-objs += singletouch.o ++ipts-objs += stylus.o +diff --git a/drivers/input/touchscreen/ipts/context.h b/drivers/input/touchscreen/ipts/context.h +new file mode 100644 +index 0000000000000..ab26552579a5c +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/context.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_CONTEXT_H_ ++#define _IPTS_CONTEXT_H_ ++ ++#include ++#include ++#include ++#include ++ ++#include "protocol/commands.h" ++#include "protocol/responses.h" ++ ++/* HACK: Workaround for DKMS build without BUS_MEI patch */ ++#ifndef BUS_MEI ++#define BUS_MEI 0x44 ++#endif ++ ++/* IPTS driver states */ ++enum ipts_host_status { ++ IPTS_HOST_STATUS_NONE, ++ IPTS_HOST_STATUS_INIT, ++ IPTS_HOST_STATUS_RESOURCE_READY, ++ IPTS_HOST_STATUS_STARTED, ++ IPTS_HOST_STATUS_STOPPING, ++ IPTS_HOST_STATUS_RESTARTING ++}; ++ ++struct ipts_buffer_info { ++ u8 *address; ++ dma_addr_t dma_address; ++}; ++ ++struct ipts_context { ++ struct mei_cl_device *client_dev; ++ struct device *dev; ++ struct ipts_device_info device_info; ++ ++ enum ipts_host_status status; ++ enum ipts_sensor_mode mode; ++ ++ struct ipts_buffer_info data[16]; ++ struct ipts_buffer_info feedback[16]; ++ struct ipts_buffer_info doorbell; ++ ++ /* ++ * These buffers are not actually used by anything, but they need ++ * to be allocated and passed to the ME to get proper functionality. ++ */ ++ struct ipts_buffer_info workqueue; ++ struct ipts_buffer_info host2me; ++ ++ struct task_struct *receiver_loop; ++ struct task_struct *data_loop; ++ ++ struct input_dev *stylus; ++ struct input_dev *singletouch; ++}; ++ ++#endif /* _IPTS_CONTEXT_H_ */ +diff --git a/drivers/input/touchscreen/ipts/control.c b/drivers/input/touchscreen/ipts/control.c +new file mode 100644 +index 0000000000000..9179eca665585 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/control.c +@@ -0,0 +1,94 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++ ++#include "context.h" ++#include "data.h" ++#include "params.h" ++#include "protocol/commands.h" ++#include "protocol/events.h" ++#include "protocol/feedback.h" ++#include "resources.h" ++ ++int ipts_control_send(struct ipts_context *ipts, ++ u32 cmd, void *data, u32 size) ++{ ++ int ret; ++ struct ipts_command msg; ++ ++ memset(&msg, 0, sizeof(struct ipts_command)); ++ msg.code = cmd; ++ ++ // Copy message payload ++ if (data && size > 0) ++ memcpy(&msg.data, data, size); ++ ++ ret = mei_cldev_send(ipts->client_dev, (u8 *)&msg, ++ sizeof(msg.code) + size); ++ if (ret < 0) { ++ dev_err(ipts->dev, "%s: error 0x%X:%d\n", __func__, cmd, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int ipts_control_send_feedback(struct ipts_context *ipts, ++ u32 buffer, u32 transaction) ++{ ++ struct ipts_buffer_info feedback_buffer; ++ struct ipts_feedback *feedback; ++ struct ipts_feedback_cmd cmd; ++ ++ feedback_buffer = ipts->feedback[buffer]; ++ feedback = (struct ipts_feedback *)feedback_buffer.address; ++ ++ memset(feedback, 0, sizeof(struct ipts_feedback)); ++ memset(&cmd, 0, sizeof(struct ipts_feedback_cmd)); ++ ++ feedback->type = IPTS_FEEDBACK_TYPE_NONE; ++ feedback->transaction = transaction; ++ ++ cmd.buffer = buffer; ++ cmd.transaction = transaction; ++ ++ return ipts_control_send(ipts, IPTS_CMD(FEEDBACK), ++ &cmd, sizeof(struct ipts_feedback_cmd)); ++} ++ ++int ipts_control_start(struct ipts_context *ipts) ++{ ++ ipts->status = IPTS_HOST_STATUS_INIT; ++ ++ if (ipts_params.singletouch) ++ ipts->mode = IPTS_SENSOR_MODE_SINGLETOUCH; ++ else ++ ipts->mode = IPTS_SENSOR_MODE_MULTITOUCH; ++ ++ return ipts_control_send(ipts, IPTS_CMD(NOTIFY_DEV_READY), NULL, 0); ++} ++ ++void ipts_control_stop(struct ipts_context *ipts) ++{ ++ enum ipts_host_status old_status = ipts->status; ++ ++ ipts->status = IPTS_HOST_STATUS_STOPPING; ++ ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0); ++ ipts_control_send(ipts, IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0); ++ ++ if (old_status < IPTS_HOST_STATUS_RESOURCE_READY) ++ return; ++ ++ ipts_data_free(ipts); ++ ipts_resources_free(ipts); ++} ++ ++int ipts_control_restart(struct ipts_context *ipts) ++{ ++ dev_info(ipts->dev, "Restarting IPTS\n"); ++ ipts_control_stop(ipts); ++ ++ ipts->status = IPTS_HOST_STATUS_RESTARTING; ++ return ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0); ++} +diff --git a/drivers/input/touchscreen/ipts/control.h b/drivers/input/touchscreen/ipts/control.h +new file mode 100644 +index 0000000000000..e57609c85d62a +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/control.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_CONTROL_H_ ++#define _IPTS_CONTROL_H_ ++ ++#include ++ ++#include "context.h" ++ ++int ipts_control_start(struct ipts_context *ipts); ++void ipts_control_stop(struct ipts_context *ipts); ++int ipts_control_restart(struct ipts_context *ipts); ++int ipts_control_send(struct ipts_context *ipts, ++ u32 cmd, void *data, u32 size); ++int ipts_control_send_feedback(struct ipts_context *ipts, ++ u32 buffer, u32 transaction); ++ ++#endif /* _IPTS_CONTROL_H_ */ +diff --git a/drivers/input/touchscreen/ipts/data.c b/drivers/input/touchscreen/ipts/data.c +new file mode 100644 +index 0000000000000..568bf04f7ea6e +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/data.c +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "hid.h" ++#include "params.h" ++#include "payload.h" ++#include "protocol/data.h" ++ ++static void ipts_data_handle_input(struct ipts_context *ipts, int buffer_id) ++{ ++ struct ipts_buffer_info buffer; ++ struct ipts_data *data; ++ ++ buffer = ipts->data[buffer_id]; ++ data = (struct ipts_data *)buffer.address; ++ ++ if (ipts_params.debug) { ++ dev_info(ipts->dev, "Buffer %d\n", buffer_id); ++ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 32, 1, ++ data->data, data->size, false); ++ } ++ ++ switch (data->type) { ++ case IPTS_DATA_TYPE_PAYLOAD: ++ ipts_payload_handle_input(ipts, data); ++ break; ++ case IPTS_DATA_TYPE_HID_REPORT: ++ ipts_hid_handle_input(ipts, data); ++ break; ++ default: ++ // ignore ++ break; ++ } ++ ++ ipts_control_send_feedback(ipts, buffer_id, data->transaction); ++} ++ ++int ipts_data_loop(void *data) ++{ ++ time64_t timeout; ++ u32 doorbell; ++ u32 last_doorbell; ++ struct ipts_context *ipts; ++ ++ timeout = ktime_get_seconds() + 5; ++ ipts = (struct ipts_context *)data; ++ last_doorbell = 0; ++ doorbell = 0; ++ ++ dev_info(ipts->dev, "Starting data loop\n"); ++ ++ while (!kthread_should_stop()) { ++ if (ipts->status != IPTS_HOST_STATUS_STARTED) { ++ msleep(1000); ++ continue; ++ } ++ ++ // IPTS will increment the doorbell after if filled up one of ++ // the data buffers. If the doorbell didn't change, there is ++ // no work for us to do. Otherwise, the value of the doorbell ++ // will stand for the *next* buffer thats going to be filled. ++ doorbell = *(u32 *)ipts->doorbell.address; ++ if (doorbell == last_doorbell) ++ goto sleep; ++ ++ timeout = ktime_get_seconds() + 5; ++ ++ while (last_doorbell != doorbell) { ++ ipts_data_handle_input(ipts, last_doorbell % 16); ++ last_doorbell++; ++ } ++sleep: ++ if (timeout > ktime_get_seconds()) ++ usleep_range(5000, 30000); ++ else ++ msleep(200); ++ } ++ ++ dev_info(ipts->dev, "Stopping data loop\n"); ++ return 0; ++} ++ ++int ipts_data_init(struct ipts_context *ipts) ++{ ++ int ret; ++ ++ ret = ipts_payload_init(ipts); ++ if (ret) ++ return ret; ++ ++ ret = ipts_hid_init(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++void ipts_data_free(struct ipts_context *ipts) ++{ ++ ipts_payload_free(ipts); ++ ipts_hid_free(ipts); ++} +diff --git a/drivers/input/touchscreen/ipts/data.h b/drivers/input/touchscreen/ipts/data.h +new file mode 100644 +index 0000000000000..fa72c1be09451 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/data.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_DATA_H_ ++#define _IPTS_DATA_H_ ++ ++#include "context.h" ++ ++int ipts_data_loop(void *data); ++int ipts_data_init(struct ipts_context *ipts); ++void ipts_data_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_DATA_H_ */ +diff --git a/drivers/input/touchscreen/ipts/hid.c b/drivers/input/touchscreen/ipts/hid.c +new file mode 100644 +index 0000000000000..2642990b8c420 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/hid.c +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include "context.h" ++#include "protocol/data.h" ++#include "singletouch.h" ++ ++/* ++ * IPTS on surface gen7 appears to make heavy use of HID reports, unlike ++ * previous generations. This file can be used to implement handling for ++ * them in the future, seperated from the actual singletouch implementation. ++ */ ++ ++void ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data) ++{ ++ // Make sure that we only handle singletouch inputs ++ // 40 is the report id of the singletouch device in the generic ++ // IPTS HID descriptor. ++ if (data->data[0] != 0x40) ++ return; ++ ++ ipts_singletouch_handle_input(ipts, data); ++} ++ ++int ipts_hid_init(struct ipts_context *ipts) ++{ ++ int ret; ++ ++ ret = ipts_singletouch_init(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++void ipts_hid_free(struct ipts_context *ipts) ++{ ++ ipts_singletouch_free(ipts); ++} +diff --git a/drivers/input/touchscreen/ipts/hid.h b/drivers/input/touchscreen/ipts/hid.h +new file mode 100644 +index 0000000000000..e6cf38fce4541 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/hid.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_HID_H_ ++#define _IPTS_HID_H_ ++ ++#include "context.h" ++#include "protocol/data.h" ++ ++int ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data); ++int ipts_hid_init(struct ipts_context *ipts); ++void ipts_hid_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_HID_H_ */ +diff --git a/drivers/input/touchscreen/ipts/init.c b/drivers/input/touchscreen/ipts/init.c +new file mode 100644 +index 0000000000000..fb70d55542af7 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/init.c +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "data.h" ++#include "receiver.h" ++ ++#define IPTS_MEI_UUID UUID_LE(0x3e8d0870, 0x271a, 0x4208, \ ++ 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04) ++ ++static int ipts_init_probe(struct mei_cl_device *cldev, ++ const struct mei_cl_device_id *id) ++{ ++ int ret; ++ struct ipts_context *ipts = NULL; ++ ++ dev_info(&cldev->dev, "Probing IPTS\n"); ++ ++ // Setup the DMA bit mask ++ if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) { ++ dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(64)\n"); ++ } else if (!dma_coerce_mask_and_coherent(&cldev->dev, ++ DMA_BIT_MASK(32))) { ++ dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(32)"); ++ } else { ++ dev_err(&cldev->dev, "No suitable DMA for IPTS available\n"); ++ return -EFAULT; ++ } ++ ++ ret = mei_cldev_enable(cldev); ++ if (ret) { ++ dev_err(&cldev->dev, "Cannot enable IPTS\n"); ++ return ret; ++ } ++ ++ ipts = devm_kzalloc(&cldev->dev, ++ sizeof(struct ipts_context), GFP_KERNEL); ++ if (!ipts) { ++ mei_cldev_disable(cldev); ++ return -ENOMEM; ++ } ++ ++ ipts->client_dev = cldev; ++ ipts->dev = &cldev->dev; ++ ++ mei_cldev_set_drvdata(cldev, ipts); ++ ++ ipts->receiver_loop = kthread_run(ipts_receiver_loop, (void *)ipts, ++ "ipts_receiver_loop"); ++ ipts->data_loop = kthread_run(ipts_data_loop, (void *)ipts, ++ "ipts_data_loop"); ++ ++ ipts_control_start(ipts); ++ ++ return 0; ++} ++ ++static int ipts_init_remove(struct mei_cl_device *cldev) ++{ ++ struct ipts_context *ipts = mei_cldev_get_drvdata(cldev); ++ ++ dev_info(&cldev->dev, "Removing IPTS\n"); ++ ++ ipts_control_stop(ipts); ++ mei_cldev_disable(cldev); ++ kthread_stop(ipts->receiver_loop); ++ kthread_stop(ipts->data_loop); ++ ++ return 0; ++} ++ ++static struct mei_cl_device_id ipts_device_id[] = { ++ { "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(mei, ipts_device_id); ++ ++static struct mei_cl_driver ipts_driver = { ++ .id_table = ipts_device_id, ++ .name = "ipts", ++ .probe = ipts_init_probe, ++ .remove = ipts_init_remove, ++}; ++module_mei_cl_driver(ipts_driver); ++ ++MODULE_DESCRIPTION("IPTS touchscreen driver"); ++MODULE_AUTHOR("Dorian Stoll "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/input/touchscreen/ipts/math.c b/drivers/input/touchscreen/ipts/math.c +new file mode 100644 +index 0000000000000..df956e5447e03 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/math.c +@@ -0,0 +1,103 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++#include ++#include ++ ++#include "math.h" ++ ++/* ++ * Since we need to work with [-pi, pi] in the atan functions, we are using ++ * 1 << 29 for the fixed point numbers. This allows us to store numbers from ++ * [-4, 4] using the full 32-bit signed integer range. ++ * ++ * Some constants such as PI have been already converted to the fixed-point ++ * format and are defined in math.h. ++ */ ++ ++static inline s32 ipts_math_mul(s32 x, s32 y) ++{ ++ return (x * (s64)y) >> 29; ++} ++ ++static inline s32 ipts_math_div(s32 x, s32 y) ++{ ++ return ((s64)x << 29) / y; ++} ++ ++static s32 ipts_math_atan(s32 x) ++{ ++ s32 tmp = ipts_math_mul( ++ ipts_math_mul(x, (abs(x) - (1 << 29))), ++ CONST_2447 + ipts_math_mul(CONST_0663, abs(x))); ++ ++ return ipts_math_mul(M_PI_4, x) - tmp; ++} ++ ++static s32 ipts_math_atan2(s32 y, s32 x) ++{ ++ s32 z; ++ ++ if (x != 0) { ++ if (abs(x) > abs(y)) { ++ z = ipts_math_div(y, x); ++ if (x > 0) ++ return ipts_math_atan(z); ++ else if (y >= 0) ++ return ipts_math_atan(z) + M_PI; ++ else ++ return ipts_math_atan(z) - M_PI; ++ } else { ++ z = ipts_math_div(x, y); ++ if (y > 0) ++ return -ipts_math_atan(z) + M_PI_2; ++ else ++ return -ipts_math_atan(z) - M_PI_2; ++ } ++ } else { ++ if (y > 0) ++ return M_PI_2; ++ else if (y < 0) ++ return -M_PI_2; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Convert altitude in range [0, 9000] and azimuth in range [0, 36000] ++ * to x-/y-tilt in range [-9000, 9000]. Azimuth is given ++ * counter-clockwise, starting with zero on the right. Altitude is ++ * given as angle between stylus and z-axis. ++ */ ++void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty) ++{ ++ s32 sin_alt, cos_alt; ++ s32 sin_azm, cos_azm; ++ ++ s32 x, y, z; ++ s64 atan_x, atan_y; ++ ++ sin_alt = fixp_sin32_rad(alt, 36000) / 4; ++ sin_azm = fixp_sin32_rad(azm, 36000) / 4; ++ ++ cos_alt = fixp_cos32_rad(alt, 36000) / 4; ++ cos_azm = fixp_cos32_rad(azm, 36000) / 4; ++ ++ x = ipts_math_mul(sin_alt, cos_azm); ++ y = ipts_math_mul(sin_alt, sin_azm); ++ z = cos_alt; ++ ++ atan_x = ipts_math_atan2(z, x); ++ atan_y = ipts_math_atan2(z, y); ++ ++ atan_x = atan_x * 4500; ++ atan_y = atan_y * 4500; ++ ++ atan_x = atan_x / M_PI_4; ++ atan_y = atan_y / M_PI_4; ++ ++ *tx = 9000 - atan_x; ++ *ty = atan_y - 9000; ++} +diff --git a/drivers/input/touchscreen/ipts/math.h b/drivers/input/touchscreen/ipts/math.h +new file mode 100644 +index 0000000000000..8e831074ab60b +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/math.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_MATH_H_ ++#define _IPTS_MATH_H_ ++ ++#include ++ ++/* (pi / 4) * (1 << 29) */ ++#define M_PI_4 421657428 ++#define M_PI_2 (M_PI_4 * 2) ++#define M_PI (M_PI_2 * 2) ++ ++/* 0.2447 * (1 << 29) */ ++#define CONST_2447 131372312 ++ ++/* 0.0663 * (1 << 29) */ ++#define CONST_0663 35594541 ++ ++void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty); ++ ++#endif /* _IPTS_MATH_H_ */ +diff --git a/drivers/input/touchscreen/ipts/params.c b/drivers/input/touchscreen/ipts/params.c +new file mode 100644 +index 0000000000000..6aa3f5cf1d762 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/params.c +@@ -0,0 +1,27 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++ ++#include "params.h" ++ ++#define IPTS_PARM(NAME, TYPE, PERM) \ ++ module_param_named(NAME, ipts_params.NAME, TYPE, PERM) ++ ++#define IPTS_DESC(NAME, DESC) \ ++ MODULE_PARM_DESC(NAME, DESC) ++ ++struct ipts_modparams ipts_params = { ++ .debug = false, ++ .singletouch = false, ++}; ++ ++IPTS_PARM(debug, bool, 0400); ++IPTS_DESC(debug, ++ "Enable additional debugging in the IPTS driver (default: false)" ++); ++ ++IPTS_PARM(singletouch, bool, 0400); ++IPTS_DESC(singletouch, ++ "Enables IPTS single touch mode (disables stylus) (default: false)" ++); +diff --git a/drivers/input/touchscreen/ipts/params.h b/drivers/input/touchscreen/ipts/params.h +new file mode 100644 +index 0000000000000..1f992a3bc21b9 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/params.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PARAMS_H_ ++#define _IPTS_PARAMS_H_ ++ ++#include ++ ++struct ipts_modparams { ++ bool debug; ++ bool singletouch; ++}; ++ ++extern struct ipts_modparams ipts_params; ++ ++#endif /* _IPTS_PARAMS_H_ */ +diff --git a/drivers/input/touchscreen/ipts/payload.c b/drivers/input/touchscreen/ipts/payload.c +new file mode 100644 +index 0000000000000..3572ddc0f2fb0 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/payload.c +@@ -0,0 +1,52 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++ ++#include "context.h" ++#include "protocol/data.h" ++#include "protocol/payload.h" ++#include "stylus.h" ++ ++void ipts_payload_handle_input(struct ipts_context *ipts, ++ struct ipts_data *data) ++{ ++ u32 i, offset; ++ struct ipts_payload *payload; ++ struct ipts_payload_frame *frame; ++ ++ payload = (struct ipts_payload *)data->data; ++ offset = 0; ++ ++ for (i = 0; i < payload->num_frames; i++) { ++ frame = (struct ipts_payload_frame *)&payload->data[offset]; ++ offset += sizeof(struct ipts_payload_frame) + frame->size; ++ ++ switch (frame->type) { ++ case IPTS_PAYLOAD_FRAME_TYPE_STYLUS: ++ ipts_stylus_handle_input(ipts, frame); ++ break; ++ case IPTS_PAYLOAD_FRAME_TYPE_TOUCH: ++ // ignored (for the moment) ++ break; ++ default: ++ // ignored ++ break; ++ } ++ } ++} ++ ++int ipts_payload_init(struct ipts_context *ipts) ++{ ++ int ret; ++ ++ ret = ipts_stylus_init(ipts); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++void ipts_payload_free(struct ipts_context *ipts) ++{ ++ ipts_stylus_free(ipts); ++} +diff --git a/drivers/input/touchscreen/ipts/payload.h b/drivers/input/touchscreen/ipts/payload.h +new file mode 100644 +index 0000000000000..6603714bb6fd0 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/payload.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PAYLOAD_H_ ++#define _IPTS_PAYLOAD_H_ ++ ++#include "context.h" ++#include "protocol/data.h" ++ ++void ipts_payload_handle_input(struct ipts_context *ipts, ++ struct ipts_data *data); ++int ipts_payload_init(struct ipts_context *ipts); ++void ipts_payload_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_PAYLOAD_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/commands.h b/drivers/input/touchscreen/ipts/protocol/commands.h +new file mode 100644 +index 0000000000000..2533dfb13584a +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/commands.h +@@ -0,0 +1,61 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_COMMANDS_H_ ++#define _IPTS_PROTOCOL_COMMANDS_H_ ++ ++#include ++#include ++ ++enum ipts_sensor_mode { ++ IPTS_SENSOR_MODE_SINGLETOUCH = 0, ++ IPTS_SENSOR_MODE_MULTITOUCH, ++ IPTS_SENSOR_MODE_MAX ++}; ++ ++struct ipts_set_mode_cmd { ++ u32 sensor_mode; ++ u8 reserved[12]; ++} __packed; ++ ++struct ipts_set_mem_window_cmd { ++ u32 data_buffer_addr_lower[16]; ++ u32 data_buffer_addr_upper[16]; ++ u32 workqueue_addr_lower; ++ u32 workqueue_addr_upper; ++ u32 doorbell_addr_lower; ++ u32 doorbell_addr_upper; ++ u32 feedback_buffer_addr_lower[16]; ++ u32 feedback_buffer_addr_upper[16]; ++ u32 host2me_addr_lower; ++ u32 host2me_addr_upper; ++ u32 host2me_size; ++ u8 reserved1; ++ u8 workqueue_item_size; ++ u16 workqueue_size; ++ u8 reserved[32]; ++} __packed; ++ ++struct ipts_feedback_cmd { ++ u32 buffer; ++ u32 transaction; ++ u8 reserved[8]; ++} __packed; ++ ++/* ++ * Commands are sent from the host to the ME ++ */ ++struct ipts_command { ++ u32 code; ++ union { ++ struct ipts_set_mode_cmd set_mode; ++ struct ipts_set_mem_window_cmd set_mem_window; ++ struct ipts_feedback_cmd feedback; ++ } data; ++} __packed; ++ ++static_assert(sizeof(struct ipts_set_mode_cmd) == 16); ++static_assert(sizeof(struct ipts_set_mem_window_cmd) == 320); ++static_assert(sizeof(struct ipts_feedback_cmd) == 16); ++static_assert(sizeof(struct ipts_command) == 324); ++ ++#endif /* _IPTS_PROTOCOL_COMMANDS_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/data.h b/drivers/input/touchscreen/ipts/protocol/data.h +new file mode 100644 +index 0000000000000..148e0545b2e4e +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/data.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_DATA_H_ ++#define _IPTS_PROTOCOL_DATA_H_ ++ ++#include ++#include ++ ++enum ipts_data_type { ++ IPTS_DATA_TYPE_PAYLOAD = 0, ++ IPTS_DATA_TYPE_ERROR, ++ IPTS_DATA_TYPE_VENDOR_DATA, ++ IPTS_DATA_TYPE_HID_REPORT, ++ IPTS_DATA_TYPE_GET_FEATURES, ++ IPTS_DATA_TYPE_MAX ++}; ++ ++struct ipts_data { ++ u32 type; ++ u32 size; ++ u32 buffer; ++ u8 reserved1[20]; ++ u8 transaction; ++ u8 reserved2[31]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_data) == 64); ++ ++#endif /* _IPTS_PROTOCOL_DATA_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/events.h b/drivers/input/touchscreen/ipts/protocol/events.h +new file mode 100644 +index 0000000000000..f8b771f90bd2b +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/events.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_EVENTS_H_ ++#define _IPTS_PROTOCOL_EVENTS_H_ ++ ++/* ++ * Helpers to avoid writing boilerplate code. ++ * The response to a command code is always 0x8000000x, where x ++ * is the command code itself. Instead of writing two definitions, ++ * we use macros to calculate the value on the fly instead. ++ */ ++#define IPTS_CMD(COMMAND) IPTS_EVT_##COMMAND ++#define IPTS_RSP(COMMAND) (IPTS_CMD(COMMAND) + 0x80000000) ++ ++/* ++ * Events that can be sent to / received from the ME ++ */ ++enum ipts_evt_code { ++ IPTS_EVT_GET_DEVICE_INFO = 1, ++ IPTS_EVT_SET_MODE, ++ IPTS_EVT_SET_MEM_WINDOW, ++ IPTS_EVT_QUIESCE_IO, ++ IPTS_EVT_READY_FOR_DATA, ++ IPTS_EVT_FEEDBACK, ++ IPTS_EVT_CLEAR_MEM_WINDOW, ++ IPTS_EVT_NOTIFY_DEV_READY, ++}; ++ ++#endif /* _IPTS_PROTOCOL_EVENTS_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/feedback.h b/drivers/input/touchscreen/ipts/protocol/feedback.h +new file mode 100644 +index 0000000000000..8b3d8b689ee83 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/feedback.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_FEEDBACK_H_ ++#define _IPTS_PROTOCOL_FEEDBACK_H_ ++ ++#include ++#include ++ ++enum ipts_feedback_type { ++ IPTS_FEEDBACK_TYPE_NONE = 0, ++ IPTS_FEEDBACK_TYPE_SOFT_RESET, ++ IPTS_FEEDBACK_TYPE_GOTO_ARMED, ++ IPTS_FEEDBACK_TYPE_GOTO_SENSING, ++ IPTS_FEEDBACK_TYPE_GOTO_SLEEP, ++ IPTS_FEEDBACK_TYPE_GOTO_DOZE, ++ IPTS_FEEDBACK_TYPE_HARD_RESET, ++ IPTS_FEEDBACK_TYPE_MAX ++}; ++ ++struct ipts_feedback { ++ u32 type; ++ u32 size; ++ u32 transaction; ++ u8 reserved[52]; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_feedback) == 64); ++ ++#endif /* _IPTS_PROTOCOL_FEEDBACK_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/payload.h b/drivers/input/touchscreen/ipts/protocol/payload.h +new file mode 100644 +index 0000000000000..f46da4ea81f25 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/payload.h +@@ -0,0 +1,47 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_PAYLOAD_H_ ++#define _IPTS_PROTOCOL_PAYLOAD_H_ ++ ++#include ++#include ++ ++enum ipts_payload_frame_type { ++ IPTS_PAYLOAD_FRAME_TYPE_STYLUS = 6, ++ IPTS_PAYLOAD_FRAME_TYPE_TOUCH = 8, ++}; ++ ++enum ipts_report_type { ++ IPTS_REPORT_TYPE_TOUCH_HEATMAP_DIM = 0x0403, ++ IPTS_REPORT_TYPE_TOUCH_HEATMAP = 0x0425, ++ IPTS_REPORT_TYPE_STYLUS_NO_TILT = 0x0410, ++ IPTS_REPORT_TYPE_STYLUS_TILT = 0x0461, ++ IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL = 0x0460, ++}; ++ ++struct ipts_payload { ++ u32 counter; ++ u32 num_frames; ++ u8 reserved[4]; ++ u8 data[]; ++} __packed; ++ ++struct ipts_payload_frame { ++ u16 index; ++ u16 type; ++ u32 size; ++ u8 reserved[8]; ++ u8 data[]; ++} __packed; ++ ++struct ipts_report { ++ u16 type; ++ u16 size; ++ u8 data[]; ++} __packed; ++ ++static_assert(sizeof(struct ipts_payload) == 12); ++static_assert(sizeof(struct ipts_payload_frame) == 16); ++static_assert(sizeof(struct ipts_report) == 4); ++ ++#endif /* _IPTS_PROTOCOL_PAYLOAD_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/responses.h b/drivers/input/touchscreen/ipts/protocol/responses.h +new file mode 100644 +index 0000000000000..27153d82a5d67 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/responses.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_RESPONSES_H_ ++#define _IPTS_PROTOCOL_RESPONSES_H_ ++ ++#include ++#include ++ ++enum ipts_me_status { ++ IPTS_ME_STATUS_SUCCESS = 0, ++ IPTS_ME_STATUS_INVALID_PARAMS, ++ IPTS_ME_STATUS_ACCESS_DENIED, ++ IPTS_ME_STATUS_CMD_SIZE_ERROR, ++ IPTS_ME_STATUS_NOT_READY, ++ IPTS_ME_STATUS_REQUEST_OUTSTANDING, ++ IPTS_ME_STATUS_NO_SENSOR_FOUND, ++ IPTS_ME_STATUS_OUT_OF_MEMORY, ++ IPTS_ME_STATUS_INTERNAL_ERROR, ++ IPTS_ME_STATUS_SENSOR_DISABLED, ++ IPTS_ME_STATUS_COMPAT_CHECK_FAIL, ++ IPTS_ME_STATUS_SENSOR_EXPECTED_RESET, ++ IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET, ++ IPTS_ME_STATUS_RESET_FAILED, ++ IPTS_ME_STATUS_TIMEOUT, ++ IPTS_ME_STATUS_TEST_MODE_FAIL, ++ IPTS_ME_STATUS_SENSOR_FAIL_FATAL, ++ IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL, ++ IPTS_ME_STATUS_INVALID_DEVICE_CAPS, ++ IPTS_ME_STATUS_QUIESCE_IO_IN_PROGRESS, ++ IPTS_ME_STATUS_MAX ++}; ++ ++struct ipts_device_info { ++ u16 vendor_id; ++ u16 device_id; ++ u32 hw_rev; ++ u32 fw_rev; ++ ++ /* Required size of one touch data buffer */ ++ u32 data_size; ++ ++ /* Required size of one feedback buffer */ ++ u32 feedback_size; ++ u8 reserved[24]; ++} __packed; ++ ++/* ++ * Responses are sent from the ME to the host, reacting to a command. ++ */ ++struct ipts_response { ++ u32 code; ++ u32 status; ++ union { ++ struct ipts_device_info device_info; ++ u8 reserved[80]; ++ } data; ++} __packed; ++ ++static_assert(sizeof(struct ipts_device_info) == 44); ++static_assert(sizeof(struct ipts_response) == 88); ++ ++#endif /* _IPTS_PROTOCOL_RESPONSES_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/singletouch.h b/drivers/input/touchscreen/ipts/protocol/singletouch.h +new file mode 100644 +index 0000000000000..bf9912ee2af4c +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/singletouch.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_SINGLETOUCH_H_ ++#define _IPTS_PROTOCOL_SINGLETOUCH_H_ ++ ++#include ++#include ++ ++struct ipts_singletouch_report { ++ u8 touch; ++ u16 x; ++ u16 y; ++} __packed; ++ ++static_assert(sizeof(struct ipts_singletouch_report) == 5); ++ ++#endif /* _IPTS_PROTOCOL_SINGLETOUCH_H_ */ +diff --git a/drivers/input/touchscreen/ipts/protocol/stylus.h b/drivers/input/touchscreen/ipts/protocol/stylus.h +new file mode 100644 +index 0000000000000..950850b365dfb +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/protocol/stylus.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_PROTOCOL_STYLUS_H_ ++#define _IPTS_PROTOCOL_STYLUS_H_ ++ ++#include ++#include ++ ++struct ipts_stylus_report { ++ u8 reports; ++ u8 reserved[3]; ++ u8 data[]; ++} __packed; ++ ++struct ipts_stylus_report_serial { ++ u8 reports; ++ u8 reserved[3]; ++ u32 serial; ++ u8 data[]; ++} __packed; ++ ++struct ipts_stylus_report_data { ++ u16 timestamp; ++ u16 mode; ++ u16 x; ++ u16 y; ++ u16 pressure; ++ u16 altitude; ++ u16 azimuth; ++ u16 reserved; ++} __packed; ++ ++struct ipts_stylus_report_data_no_tilt { ++ u8 reserved[4]; ++ u8 mode; ++ u16 x; ++ u16 y; ++ u16 pressure; ++ u8 reserved2; ++} __packed; ++ ++#define IPTS_STYLUS_REPORT_MODE_PROX BIT(0) ++#define IPTS_STYLUS_REPORT_MODE_TOUCH BIT(1) ++#define IPTS_STYLUS_REPORT_MODE_BUTTON BIT(2) ++#define IPTS_STYLUS_REPORT_MODE_ERASER BIT(3) ++ ++static_assert(sizeof(struct ipts_stylus_report) == 4); ++static_assert(sizeof(struct ipts_stylus_report_serial) == 8); ++static_assert(sizeof(struct ipts_stylus_report_data) == 16); ++static_assert(sizeof(struct ipts_stylus_report_data_no_tilt) == 12); ++ ++#endif /* _IPTS_PAYLOAD_STYLUS_H_ */ +diff --git a/drivers/input/touchscreen/ipts/receiver.c b/drivers/input/touchscreen/ipts/receiver.c +new file mode 100644 +index 0000000000000..ab283994c3e5f +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/receiver.c +@@ -0,0 +1,265 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++ ++#include "context.h" ++#include "control.h" ++#include "data.h" ++#include "protocol/commands.h" ++#include "protocol/events.h" ++#include "protocol/responses.h" ++#include "resources.h" ++ ++static void ipts_receiver_handle_notify_dev_ready(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status) ++{ ++ if (msg->status != IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL && ++ msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ *cmd_status = ipts_control_send(ipts, ++ IPTS_CMD(GET_DEVICE_INFO), NULL, 0); ++} ++ ++static void ipts_receiver_handle_get_device_info(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status) ++{ ++ if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL && ++ msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ memcpy(&ipts->device_info, &msg->data.device_info, ++ sizeof(struct ipts_device_info)); ++ ++ dev_info(ipts->dev, "Device %04hX:%04hX found\n", ++ ipts->device_info.vendor_id, ++ ipts->device_info.device_id); ++ ++ if (ipts_data_init(ipts)) ++ return; ++ ++ *cmd_status = ipts_control_send(ipts, ++ IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0); ++} ++ ++static void ipts_receiver_handle_clear_mem_window(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status, int *ret) ++{ ++ struct ipts_set_mode_cmd sensor_mode_cmd; ++ ++ if (msg->status != IPTS_ME_STATUS_TIMEOUT && ++ msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ if (ipts->status == IPTS_HOST_STATUS_STOPPING) ++ return; ++ ++ if (ipts_resources_init(ipts)) ++ return; ++ ++ ipts->status = IPTS_HOST_STATUS_RESOURCE_READY; ++ ++ memset(&sensor_mode_cmd, 0, sizeof(struct ipts_set_mode_cmd)); ++ sensor_mode_cmd.sensor_mode = ipts->mode; ++ ++ *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MODE), ++ &sensor_mode_cmd, sizeof(struct ipts_set_mode_cmd)); ++} ++ ++static void ipts_receiver_handle_set_mode(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status) ++{ ++ int i; ++ struct ipts_set_mem_window_cmd cmd; ++ ++ if (msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ memset(&cmd, 0, sizeof(struct ipts_set_mem_window_cmd)); ++ ++ for (i = 0; i < 16; i++) { ++ cmd.data_buffer_addr_lower[i] = ++ lower_32_bits(ipts->data[i].dma_address); ++ ++ cmd.data_buffer_addr_upper[i] = ++ upper_32_bits(ipts->data[i].dma_address); ++ ++ cmd.feedback_buffer_addr_lower[i] = ++ lower_32_bits(ipts->feedback[i].dma_address); ++ ++ cmd.feedback_buffer_addr_upper[i] = ++ upper_32_bits(ipts->feedback[i].dma_address); ++ } ++ ++ cmd.workqueue_addr_lower = lower_32_bits(ipts->workqueue.dma_address); ++ cmd.workqueue_addr_upper = upper_32_bits(ipts->workqueue.dma_address); ++ ++ cmd.doorbell_addr_lower = lower_32_bits(ipts->doorbell.dma_address); ++ cmd.doorbell_addr_upper = upper_32_bits(ipts->doorbell.dma_address); ++ ++ cmd.host2me_addr_lower = lower_32_bits(ipts->host2me.dma_address); ++ cmd.host2me_addr_upper = upper_32_bits(ipts->host2me.dma_address); ++ cmd.host2me_size = ipts->device_info.data_size; ++ ++ cmd.workqueue_size = 8192; ++ cmd.workqueue_item_size = 16; ++ ++ *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MEM_WINDOW), ++ &cmd, sizeof(struct ipts_set_mem_window_cmd)); ++} ++ ++static void ipts_receiver_handle_set_mem_window(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status) ++{ ++ if (msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ *cmd_status = ipts_control_send(ipts, ++ IPTS_CMD(READY_FOR_DATA), NULL, 0); ++ if (*cmd_status) ++ return; ++ ++ ipts->status = IPTS_HOST_STATUS_STARTED; ++ dev_info(ipts->dev, "IPTS enabled\n"); ++} ++ ++static void ipts_receiver_handle_ready_for_data(struct ipts_context *ipts, ++ struct ipts_response *msg) ++{ ++ if (msg->status != IPTS_ME_STATUS_SENSOR_DISABLED && ++ msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH || ++ ipts->status != IPTS_HOST_STATUS_STARTED) ++ return; ++ ++ // Increment the doorbell manually to indicate that a new buffer ++ // filled with touch data is available ++ *((u32 *)ipts->doorbell.address) += 1; ++} ++ ++static void ipts_recever_handle_feedback(struct ipts_context *ipts, ++ struct ipts_response *msg, int *cmd_status) ++{ ++ if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL && ++ msg->status != IPTS_ME_STATUS_SUCCESS && ++ msg->status != IPTS_ME_STATUS_INVALID_PARAMS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH) ++ return; ++ ++ *cmd_status = ipts_control_send(ipts, ++ IPTS_CMD(READY_FOR_DATA), NULL, 0); ++} ++ ++static void ipts_receiver_handle_quiesce_io(struct ipts_context *ipts, ++ struct ipts_response *msg) ++{ ++ if (msg->status != IPTS_ME_STATUS_SUCCESS) { ++ dev_err(ipts->dev, "0x%08x failed - status = %d\n", ++ msg->code, msg->status); ++ return; ++ } ++ ++ if (ipts->status == IPTS_HOST_STATUS_RESTARTING) ++ ipts_control_start(ipts); ++} ++ ++ ++static int ipts_receiver_handle_response(struct ipts_context *ipts, ++ struct ipts_response *msg, u32 msg_len) ++{ ++ int cmd_status = 0; ++ int ret = 0; ++ ++ switch (msg->code) { ++ case IPTS_RSP(NOTIFY_DEV_READY): ++ ipts_receiver_handle_notify_dev_ready(ipts, msg, &cmd_status); ++ break; ++ case IPTS_RSP(GET_DEVICE_INFO): ++ ipts_receiver_handle_get_device_info(ipts, msg, &cmd_status); ++ break; ++ case IPTS_RSP(CLEAR_MEM_WINDOW): ++ ipts_receiver_handle_clear_mem_window(ipts, msg, ++ &cmd_status, &ret); ++ break; ++ case IPTS_RSP(SET_MODE): ++ ipts_receiver_handle_set_mode(ipts, msg, &cmd_status); ++ break; ++ case IPTS_RSP(SET_MEM_WINDOW): ++ ipts_receiver_handle_set_mem_window(ipts, msg, &cmd_status); ++ break; ++ case IPTS_RSP(READY_FOR_DATA): ++ ipts_receiver_handle_ready_for_data(ipts, msg); ++ break; ++ case IPTS_RSP(FEEDBACK): ++ ipts_recever_handle_feedback(ipts, msg, &cmd_status); ++ break; ++ case IPTS_RSP(QUIESCE_IO): ++ ipts_receiver_handle_quiesce_io(ipts, msg); ++ break; ++ } ++ ++ if (ipts->status == IPTS_HOST_STATUS_STOPPING) ++ return 0; ++ ++ if (msg->status == IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET || ++ msg->status == IPTS_ME_STATUS_SENSOR_EXPECTED_RESET) { ++ dev_info(ipts->dev, "Sensor has been reset: %d\n", msg->status); ++ ipts_control_restart(ipts); ++ } ++ ++ if (cmd_status) ++ ipts_control_restart(ipts); ++ ++ return ret; ++} ++ ++int ipts_receiver_loop(void *data) ++{ ++ u32 msg_len; ++ struct ipts_context *ipts; ++ struct ipts_response msg; ++ ++ ipts = (struct ipts_context *)data; ++ dev_info(ipts->dev, "Starting receive loop\n"); ++ ++ while (!kthread_should_stop()) { ++ msg_len = mei_cldev_recv(ipts->client_dev, ++ (u8 *)&msg, sizeof(msg)); ++ ++ if (msg_len <= 0) { ++ dev_err(ipts->dev, "Error in reading ME message\n"); ++ continue; ++ } ++ ++ if (ipts_receiver_handle_response(ipts, &msg, msg_len)) ++ dev_err(ipts->dev, "Error in handling ME message\n"); ++ } ++ ++ dev_info(ipts->dev, "Stopping receive loop\n"); ++ return 0; ++} +diff --git a/drivers/input/touchscreen/ipts/receiver.h b/drivers/input/touchscreen/ipts/receiver.h +new file mode 100644 +index 0000000000000..4d413a0abd4c5 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/receiver.h +@@ -0,0 +1,8 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_RECEIVER_H_ ++#define _IPTS_RECEIVER_H_ ++ ++int ipts_receiver_loop(void *data); ++ ++#endif /* _IPTS_RECEIVER_H_ */ +diff --git a/drivers/input/touchscreen/ipts/resources.c b/drivers/input/touchscreen/ipts/resources.c +new file mode 100644 +index 0000000000000..704db9fdd3fd4 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/resources.c +@@ -0,0 +1,131 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++ ++#include "context.h" ++ ++void ipts_resources_free(struct ipts_context *ipts) ++{ ++ int i; ++ u32 touch_buffer_size; ++ u32 feedback_buffer_size; ++ struct ipts_buffer_info *buffers; ++ ++ touch_buffer_size = ipts->device_info.data_size; ++ feedback_buffer_size = ipts->device_info.feedback_size; ++ ++ buffers = ipts->data; ++ for (i = 0; i < 16; i++) { ++ if (!buffers[i].address) ++ continue; ++ ++ dmam_free_coherent(ipts->dev, touch_buffer_size, ++ buffers[i].address, buffers[i].dma_address); ++ ++ buffers[i].address = 0; ++ buffers[i].dma_address = 0; ++ } ++ ++ buffers = ipts->feedback; ++ for (i = 0; i < 16; i++) { ++ if (!buffers[i].address) ++ continue; ++ ++ dmam_free_coherent(ipts->dev, feedback_buffer_size, ++ buffers[i].address, buffers[i].dma_address); ++ ++ buffers[i].address = 0; ++ buffers[i].dma_address = 0; ++ } ++ ++ if (ipts->doorbell.address) { ++ dmam_free_coherent(ipts->dev, sizeof(u32), ++ ipts->doorbell.address, ++ ipts->doorbell.dma_address); ++ ++ ipts->doorbell.address = 0; ++ ipts->doorbell.dma_address = 0; ++ } ++ ++ if (ipts->workqueue.address) { ++ dmam_free_coherent(ipts->dev, sizeof(u32), ++ ipts->workqueue.address, ++ ipts->workqueue.dma_address); ++ ++ ipts->workqueue.address = 0; ++ ipts->workqueue.dma_address = 0; ++ } ++ ++ if (ipts->host2me.address) { ++ dmam_free_coherent(ipts->dev, touch_buffer_size, ++ ipts->host2me.address, ++ ipts->host2me.dma_address); ++ ++ ipts->host2me.address = 0; ++ ipts->host2me.dma_address = 0; ++ } ++} ++ ++int ipts_resources_init(struct ipts_context *ipts) ++{ ++ int i; ++ u32 touch_buffer_size; ++ u32 feedback_buffer_size; ++ struct ipts_buffer_info *buffers; ++ ++ touch_buffer_size = ipts->device_info.data_size; ++ feedback_buffer_size = ipts->device_info.feedback_size; ++ ++ buffers = ipts->data; ++ for (i = 0; i < 16; i++) { ++ buffers[i].address = dmam_alloc_coherent(ipts->dev, ++ touch_buffer_size, ++ &buffers[i].dma_address, ++ GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!buffers[i].address) ++ goto release_resources; ++ } ++ ++ buffers = ipts->feedback; ++ for (i = 0; i < 16; i++) { ++ buffers[i].address = dmam_alloc_coherent(ipts->dev, ++ feedback_buffer_size, ++ &buffers[i].dma_address, ++ GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!buffers[i].address) ++ goto release_resources; ++ } ++ ++ ipts->doorbell.address = dmam_alloc_coherent(ipts->dev, ++ sizeof(u32), ++ &ipts->doorbell.dma_address, ++ GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!ipts->doorbell.address) ++ goto release_resources; ++ ++ ipts->workqueue.address = dmam_alloc_coherent(ipts->dev, ++ sizeof(u32), ++ &ipts->workqueue.dma_address, ++ GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!ipts->workqueue.address) ++ goto release_resources; ++ ++ ipts->host2me.address = dmam_alloc_coherent(ipts->dev, ++ touch_buffer_size, ++ &ipts->host2me.dma_address, ++ GFP_ATOMIC | __GFP_ZERO); ++ ++ if (!ipts->workqueue.address) ++ goto release_resources; ++ ++ return 0; ++ ++release_resources: ++ ++ ipts_resources_free(ipts); ++ return -ENOMEM; ++} +diff --git a/drivers/input/touchscreen/ipts/resources.h b/drivers/input/touchscreen/ipts/resources.h +new file mode 100644 +index 0000000000000..cf9807b0dbe62 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/resources.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_RESOURCES_H_ ++#define _IPTS_RESOURCES_H_ ++ ++#include "context.h" ++ ++int ipts_resources_init(struct ipts_context *ipts); ++void ipts_resources_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_RESOURCES_H_ */ +diff --git a/drivers/input/touchscreen/ipts/singletouch.c b/drivers/input/touchscreen/ipts/singletouch.c +new file mode 100644 +index 0000000000000..ed70444f649c4 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/singletouch.c +@@ -0,0 +1,64 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++ ++#include "context.h" ++#include "protocol/data.h" ++#include "protocol/singletouch.h" ++ ++void ipts_singletouch_handle_input(struct ipts_context *ipts, ++ struct ipts_data *data) ++{ ++ struct ipts_singletouch_report *report = ++ (struct ipts_singletouch_report *)&data->data[1]; ++ ++ input_report_key(ipts->singletouch, BTN_TOUCH, report->touch); ++ input_report_abs(ipts->singletouch, ABS_X, report->x); ++ input_report_abs(ipts->singletouch, ABS_Y, report->y); ++ ++ input_sync(ipts->singletouch); ++} ++ ++int ipts_singletouch_init(struct ipts_context *ipts) ++{ ++ int ret; ++ ++ ipts->singletouch = input_allocate_device(); ++ if (!ipts->singletouch) ++ return -ENOMEM; ++ ++ __set_bit(INPUT_PROP_DIRECT, ipts->singletouch->propbit); ++ ++ input_set_capability(ipts->singletouch, EV_KEY, BTN_TOUCH); ++ input_set_abs_params(ipts->singletouch, ABS_X, 0, 32767, 0, 0); ++ input_abs_set_res(ipts->singletouch, ABS_X, 112); ++ input_set_abs_params(ipts->singletouch, ABS_Y, 0, 32767, 0, 0); ++ input_abs_set_res(ipts->singletouch, ABS_Y, 199); ++ ++ ipts->singletouch->id.bustype = BUS_MEI; ++ ipts->singletouch->id.vendor = ipts->device_info.vendor_id; ++ ipts->singletouch->id.product = ipts->device_info.device_id; ++ ipts->singletouch->id.version = ipts->device_info.fw_rev; ++ ++ ipts->singletouch->phys = "heci3"; ++ ipts->singletouch->name = "IPTS Singletouch"; ++ ++ ret = input_register_device(ipts->singletouch); ++ if (ret) { ++ dev_err(ipts->dev, "Cannot register input device: %s (%d)\n", ++ ipts->singletouch->name, ret); ++ input_free_device(ipts->singletouch); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++void ipts_singletouch_free(struct ipts_context *ipts) ++{ ++ if (!ipts->singletouch) ++ return; ++ ++ input_unregister_device(ipts->singletouch); ++} +diff --git a/drivers/input/touchscreen/ipts/singletouch.h b/drivers/input/touchscreen/ipts/singletouch.h +new file mode 100644 +index 0000000000000..53207497a4628 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/singletouch.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_SINGLETOUCH_H_ ++#define _IPTS_SINGLETOUCH_H_ ++ ++#include "context.h" ++#include "protocol/data.h" ++ ++void ipts_singletouch_handle_input(struct ipts_context *ipts, ++ struct ipts_data *data); ++int ipts_singletouch_init(struct ipts_context *ipts); ++void ipts_singletouch_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_SINGLETOUCH_H_ */ +diff --git a/drivers/input/touchscreen/ipts/stylus.c b/drivers/input/touchscreen/ipts/stylus.c +new file mode 100644 +index 0000000000000..987fa756fec33 +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/stylus.c +@@ -0,0 +1,179 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++#include ++#include ++ ++#include "context.h" ++#include "math.h" ++#include "protocol/payload.h" ++#include "protocol/stylus.h" ++ ++static void ipts_stylus_handle_stylus_data(struct ipts_context *ipts, ++ struct ipts_stylus_report_data *data) ++{ ++ u8 prox = data->mode & IPTS_STYLUS_REPORT_MODE_PROX; ++ u8 touch = data->mode & IPTS_STYLUS_REPORT_MODE_TOUCH; ++ u8 button = data->mode & IPTS_STYLUS_REPORT_MODE_BUTTON; ++ u8 rubber = data->mode & IPTS_STYLUS_REPORT_MODE_ERASER; ++ ++ s32 tx = 0; ++ s32 ty = 0; ++ ++ // avoid unnecessary computations ++ // altitude is zero if stylus does not touch the screen ++ if (data->altitude) { ++ ipts_math_altitude_azimuth_to_tilt(data->altitude, ++ data->azimuth, &tx, &ty); ++ } ++ ++ input_report_key(ipts->stylus, BTN_TOUCH, touch); ++ input_report_key(ipts->stylus, BTN_TOOL_PEN, prox && !rubber); ++ input_report_key(ipts->stylus, BTN_TOOL_RUBBER, prox && rubber); ++ input_report_key(ipts->stylus, BTN_STYLUS, button); ++ ++ input_report_abs(ipts->stylus, ABS_X, data->x); ++ input_report_abs(ipts->stylus, ABS_Y, data->y); ++ input_report_abs(ipts->stylus, ABS_PRESSURE, data->pressure); ++ input_report_abs(ipts->stylus, ABS_MISC, data->timestamp); ++ ++ input_report_abs(ipts->stylus, ABS_TILT_X, tx); ++ input_report_abs(ipts->stylus, ABS_TILT_Y, ty); ++ ++ input_sync(ipts->stylus); ++} ++ ++static void ipts_stylus_handle_report_tilt_serial(struct ipts_context *ipts, ++ struct ipts_report *report) ++{ ++ int i; ++ struct ipts_stylus_report_serial *stylus_report; ++ struct ipts_stylus_report_data *data; ++ ++ stylus_report = (struct ipts_stylus_report_serial *)report->data; ++ data = (struct ipts_stylus_report_data *)stylus_report->data; ++ ++ // TODO: Track serial number and support multiple styli ++ ++ for (i = 0; i < stylus_report->reports; i++) ++ ipts_stylus_handle_stylus_data(ipts, &data[i]); ++} ++ ++static void ipts_stylus_handle_report_tilt(struct ipts_context *ipts, ++ struct ipts_report *report) ++{ ++ int i; ++ struct ipts_stylus_report *stylus_report; ++ struct ipts_stylus_report_data *data; ++ ++ stylus_report = (struct ipts_stylus_report *)report->data; ++ data = (struct ipts_stylus_report_data *)stylus_report->data; ++ ++ for (i = 0; i < stylus_report->reports; i++) ++ ipts_stylus_handle_stylus_data(ipts, &data[i]); ++} ++ ++static void ipts_stylus_handle_report_no_tilt(struct ipts_context *ipts, ++ struct ipts_report *report) ++{ ++ int i; ++ struct ipts_stylus_report_serial *stylus_report; ++ struct ipts_stylus_report_data_no_tilt *data; ++ struct ipts_stylus_report_data new_data; ++ ++ stylus_report = (struct ipts_stylus_report_serial *)report->data; ++ data = (struct ipts_stylus_report_data_no_tilt *)stylus_report->data; ++ ++ for (i = 0; i < stylus_report->reports; i++) { ++ new_data.mode = data[i].mode; ++ new_data.x = data[i].x; ++ new_data.y = data[i].y; ++ new_data.pressure = data[i].pressure * 4; ++ new_data.altitude = 0; ++ new_data.azimuth = 0; ++ new_data.timestamp = 0; ++ ++ ipts_stylus_handle_stylus_data(ipts, &new_data); ++ } ++} ++ ++void ipts_stylus_handle_input(struct ipts_context *ipts, ++ struct ipts_payload_frame *frame) ++{ ++ int size; ++ struct ipts_report *report; ++ ++ size = 0; ++ ++ while (size < frame->size) { ++ report = (struct ipts_report *)&frame->data[size]; ++ size += sizeof(struct ipts_report) + report->size; ++ ++ switch (report->type) { ++ case IPTS_REPORT_TYPE_STYLUS_NO_TILT: ++ ipts_stylus_handle_report_no_tilt(ipts, report); ++ break; ++ case IPTS_REPORT_TYPE_STYLUS_TILT: ++ ipts_stylus_handle_report_tilt(ipts, report); ++ break; ++ case IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL: ++ ipts_stylus_handle_report_tilt_serial(ipts, report); ++ break; ++ default: ++ // ignored ++ break; ++ } ++ } ++} ++ ++int ipts_stylus_init(struct ipts_context *ipts) ++{ ++ int ret; ++ ++ ipts->stylus = input_allocate_device(); ++ if (!ipts->stylus) ++ return -ENOMEM; ++ ++ __set_bit(INPUT_PROP_DIRECT, ipts->stylus->propbit); ++ __set_bit(INPUT_PROP_POINTER, ipts->stylus->propbit); ++ ++ input_set_abs_params(ipts->stylus, ABS_X, 0, 9600, 0, 0); ++ input_abs_set_res(ipts->stylus, ABS_X, 34); ++ input_set_abs_params(ipts->stylus, ABS_Y, 0, 7200, 0, 0); ++ input_abs_set_res(ipts->stylus, ABS_Y, 38); ++ input_set_abs_params(ipts->stylus, ABS_PRESSURE, 0, 4096, 0, 0); ++ input_set_abs_params(ipts->stylus, ABS_TILT_X, -9000, 9000, 0, 0); ++ input_abs_set_res(ipts->stylus, ABS_TILT_X, 5730); ++ input_set_abs_params(ipts->stylus, ABS_TILT_Y, -9000, 9000, 0, 0); ++ input_abs_set_res(ipts->stylus, ABS_TILT_Y, 5730); ++ input_set_abs_params(ipts->stylus, ABS_MISC, 0, 65535, 0, 0); ++ input_set_capability(ipts->stylus, EV_KEY, BTN_TOUCH); ++ input_set_capability(ipts->stylus, EV_KEY, BTN_STYLUS); ++ input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_PEN); ++ input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_RUBBER); ++ ++ ipts->stylus->id.bustype = BUS_MEI; ++ ipts->stylus->id.vendor = ipts->device_info.vendor_id; ++ ipts->stylus->id.product = ipts->device_info.device_id; ++ ipts->stylus->id.version = ipts->device_info.fw_rev; ++ ++ ipts->stylus->phys = "heci3"; ++ ipts->stylus->name = "IPTS Stylus"; ++ ++ ret = input_register_device(ipts->stylus); ++ if (ret) { ++ dev_err(ipts->dev, "Cannot register input device: %s (%d)\n", ++ ipts->stylus->name, ret); ++ input_free_device(ipts->stylus); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++void ipts_stylus_free(struct ipts_context *ipts) ++{ ++ if (!ipts->stylus) ++ return; ++ ++ input_unregister_device(ipts->stylus); ++} +diff --git a/drivers/input/touchscreen/ipts/stylus.h b/drivers/input/touchscreen/ipts/stylus.h +new file mode 100644 +index 0000000000000..5b93add1eac2d +--- /dev/null ++++ b/drivers/input/touchscreen/ipts/stylus.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++ ++#ifndef _IPTS_STYLUS_H_ ++#define _IPTS_STYLUS_H_ ++ ++#include "context.h" ++#include "protocol/payload.h" ++ ++void ipts_stylus_handle_input(struct ipts_context *ipts, ++ struct ipts_payload_frame *frame); ++int ipts_stylus_init(struct ipts_context *ipts); ++void ipts_stylus_free(struct ipts_context *ipts); ++ ++#endif /* _IPTS_STYLUS_H_ */ +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index e56dc47540646..a55c61c89238a 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -59,6 +59,7 @@ + + #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */ + #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */ ++#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 (iTouch) */ + #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */ + #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */ + +@@ -90,6 +91,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_4 0x34E4 /* Ice Lake Point LP 4 (iTouch) */ + + #define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */ + +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 75ab2ffbf235f..78790904d77cb 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -77,6 +77,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)}, +@@ -103,6 +104,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_4, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)}, + +diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h +index 9a61c28ed3ae4..47fc20975245d 100644 +--- a/include/uapi/linux/input.h ++++ b/include/uapi/linux/input.h +@@ -271,6 +271,7 @@ struct input_mask { + #define BUS_RMI 0x1D + #define BUS_CEC 0x1E + #define BUS_INTEL_ISHTP 0x1F ++#define BUS_MEI 0x44 + + /* + * MT_TOOL types +-- +2.26.2 + diff --git a/patches/5.4/0007-wifi.patch b/patches/5.4/0007-wifi.patch deleted file mode 100644 index bff3c5956..000000000 --- a/patches/5.4/0007-wifi.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 161c9aed6b224308438cec3aa48c896cba48b431 Mon Sep 17 00:00:00 2001 -From: sebanc <22224731+sebanc@users.noreply.github.com> -Date: Mon, 4 Nov 2019 09:30:57 +0100 -Subject: [PATCH 7/7] wifi - ---- - drivers/net/wireless/marvell/mwifiex/pcie.c | 74 ++++++++++--------- - .../net/wireless/marvell/mwifiex/sta_cmd.c | 15 +--- - 2 files changed, 41 insertions(+), 48 deletions(-) - -diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index fc1706d0647d..b3380ed75431 100644 ---- a/drivers/net/wireless/marvell/mwifiex/pcie.c -+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -149,35 +149,38 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) - */ - static int mwifiex_pcie_suspend(struct device *dev) - { -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct pcie_service_card *card = pci_get_drvdata(pdev); - struct mwifiex_adapter *adapter; -- struct pcie_service_card *card = dev_get_drvdata(dev); -- -+ struct mwifiex_private *priv; -+ const struct mwifiex_pcie_card_reg *reg; -+ u32 fw_status; -+ int ret; - - /* Might still be loading firmware */ - wait_for_completion(&card->fw_done); - - adapter = card->adapter; -- if (!adapter) { -- dev_err(dev, "adapter is not valid\n"); -+ if (!adapter || !adapter->priv_num) - return 0; -- } - -- mwifiex_enable_wake(adapter); -+ reg = card->pcie.reg; -+ if (reg) -+ ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status); -+ else -+ fw_status = -1; -+ -+ if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) { -+ mwifiex_deauthenticate_all(adapter); - -- /* Enable the Host Sleep */ -- if (!mwifiex_enable_hs(adapter)) { -- mwifiex_dbg(adapter, ERROR, -- "cmd: failed to suspend\n"); -- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); -- mwifiex_disable_wake(adapter); -- return -EFAULT; -- } -+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - -- flush_workqueue(adapter->workqueue); -+ mwifiex_disable_auto_ds(priv); - -- /* Indicate device suspended */ -- set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); -- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); -+ mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); -+ } -+ -+ mwifiex_remove_card(adapter); - - return 0; - } -@@ -192,28 +195,29 @@ static int mwifiex_pcie_suspend(struct device *dev) - */ - static int mwifiex_pcie_resume(struct device *dev) - { -- struct mwifiex_adapter *adapter; -- struct pcie_service_card *card = dev_get_drvdata(dev); -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct pcie_service_card *card = pci_get_drvdata(pdev); -+ int ret; - -+ pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", -+ pdev->vendor, pdev->device, pdev->revision); - -- if (!card->adapter) { -- dev_err(dev, "adapter structure is not valid\n"); -- return 0; -- } -+ init_completion(&card->fw_done); - -- adapter = card->adapter; -+ card->dev = pdev; - -- if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) { -- mwifiex_dbg(adapter, WARN, -- "Device already resumed\n"); -- return 0; -+ /* device tree node parsing and platform specific configuration */ -+ if (pdev->dev.of_node) { -+ ret = mwifiex_pcie_probe_of(&pdev->dev); -+ if (ret) -+ return ret; - } - -- clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); -- -- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), -- MWIFIEX_ASYNC_CMD); -- mwifiex_disable_wake(adapter); -+ if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, -+ MWIFIEX_PCIE, &pdev->dev)) { -+ pr_err("%s failed\n", __func__); -+ return -1; -+ } - - return 0; - } -@@ -267,6 +271,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return -1; - } - -+ pdev->bus->self->bridge_d3 = false; -+ - return 0; - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -index 4ed10cf82f9a..013db4386c39 100644 ---- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -@@ -2265,14 +2265,13 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, - int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) - { - struct mwifiex_adapter *adapter = priv->adapter; -- int ret; - struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; -- struct mwifiex_ds_auto_ds auto_ds; - enum state_11d_t state_11d; - struct mwifiex_ds_11n_tx_cfg tx_cfg; - u8 sdio_sp_rx_aggr_enable; - u16 packet_aggr_enable; - int data; -+ int ret; - - if (first_sta) { - if (priv->adapter->iface_type == MWIFIEX_PCIE) { -@@ -2395,18 +2394,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) - if (ret) - return -1; - -- if (!disable_auto_ds && first_sta && -- priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { -- /* Enable auto deep sleep */ -- auto_ds.auto_ds = DEEP_SLEEP_ON; -- auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; -- ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, -- EN_AUTO_PS, BITMAP_AUTO_DS, -- &auto_ds, true); -- if (ret) -- return -1; -- } -- - if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { - /* Send cmd to FW to enable/disable 11D function */ - state_11d = ENABLE_11D; --- -2.25.0 -