Jelajahi Sumber

Update patches for v5.4

Maximilian Luz 5 tahun lalu
induk
melakukan
09ab0b74bd

+ 30 - 0
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

+ 5 - 5
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 <qzed@users.noreply.github.com>
 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
 

+ 3 - 3
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
 

+ 12 - 10
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 <cwhuang@linux.org.tw>
 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
 

+ 0 - 97
patches/5.4/0004-ioremap_uc.patch

@@ -1,97 +0,0 @@
-From 83aa487e4c43e598ee3e5266e79573ba6e0a3ab7 Mon Sep 17 00:00:00 2001
-From: Tuowen Zhao <ztuowen@gmail.com>
-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
-

File diff ditekan karena terlalu besar
+ 183 - 198
patches/5.4/0004-surface-sam.patch


+ 5 - 5
patches/5.4/0006-surface-lte.patch → 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 <qzed@users.noreply.github.com>
 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
 

+ 255 - 0
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
+

+ 2061 - 0
patches/5.4/0007-ipts.patch

@@ -0,0 +1,2061 @@
+From 08f34dc84753960c03b6d4a7838752d890ef2b3b Mon Sep 17 00:00:00 2001
+From: Dorian Stoll <dorian.stoll@tmsp.io>
+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 <linux/kthread.h>
++#include <linux/input.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/types.h>
++
++#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 <linux/mei_cl_bus.h>
++#include <linux/types.h>
++
++#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 <linux/types.h>
++
++#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 <linux/delay.h>
++#include <linux/kthread.h>
++#include <linux/ktime.h>
++
++#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 <linux/dma-mapping.h>
++#include <linux/mei_cl_bus.h>
++#include <linux/module.h>
++#include <linux/mod_devicetable.h>
++
++#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 <dorian.stoll@tmsp.io>");
++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 <linux/bug.h>
++#include <linux/fixp-arith.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++
++#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 <linux/types.h>
++
++/* (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 <linux/moduleparam.h>
++#include <linux/types.h>
++
++#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 <linux/types.h>
++
++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 <linux/types.h>
++
++#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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/build_bug.h>
++#include <linux/types.h>
++
++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 <linux/types.h>
++
++#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 <linux/dma-mapping.h>
++
++#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 <linux/input.h>
++#include <linux/kernel.h>
++
++#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 <linux/input.h>
++#include <linux/kernel.h>
++
++#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
+

+ 0 - 168
patches/5.4/0007-wifi.patch

@@ -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
-

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini