2020-04-02 22:23:37 +00:00
|
|
|
From 3aab2704247a7ebd2acc49c6843aebddc67f3f20 Mon Sep 17 00:00:00 2001
|
2020-01-28 22:40:18 +00:00
|
|
|
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 ++
|
2020-03-17 01:16:47 +00:00
|
|
|
drivers/input/touchscreen/ipts/Makefile | 17 ++
|
2020-01-28 22:40:18 +00:00
|
|
|
drivers/input/touchscreen/ipts/context.h | 61 ++++
|
2020-03-17 01:16:47 +00:00
|
|
|
drivers/input/touchscreen/ipts/control.c | 94 +++++++
|
2020-01-28 22:40:18 +00:00
|
|
|
drivers/input/touchscreen/ipts/control.h | 18 ++
|
2020-03-17 01:16:47 +00:00
|
|
|
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 +
|
2020-01-28 22:40:18 +00:00
|
|
|
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 +
|
2020-03-17 01:16:47 +00:00
|
|
|
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 ++
|
2020-01-28 22:40:18 +00:00
|
|
|
.../input/touchscreen/ipts/protocol/events.h | 29 ++
|
2020-03-17 01:16:47 +00:00
|
|
|
.../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 ++
|
2020-04-02 22:23:37 +00:00
|
|
|
.../input/touchscreen/ipts/protocol/stylus.h | 52 ++++
|
2020-03-17 01:16:47 +00:00
|
|
|
drivers/input/touchscreen/ipts/receiver.c | 265 ++++++++++++++++++
|
2020-01-28 22:40:18 +00:00
|
|
|
drivers/input/touchscreen/ipts/receiver.h | 8 +
|
|
|
|
drivers/input/touchscreen/ipts/resources.c | 131 +++++++++
|
|
|
|
drivers/input/touchscreen/ipts/resources.h | 11 +
|
2020-03-17 01:16:47 +00:00
|
|
|
drivers/input/touchscreen/ipts/singletouch.c | 64 +++++
|
|
|
|
drivers/input/touchscreen/ipts/singletouch.h | 14 +
|
|
|
|
drivers/input/touchscreen/ipts/stylus.c | 191 +++++++++++++
|
|
|
|
drivers/input/touchscreen/ipts/stylus.h | 14 +
|
2020-01-28 22:40:18 +00:00
|
|
|
drivers/misc/mei/hw-me-regs.h | 2 +
|
|
|
|
drivers/misc/mei/pci-me.c | 2 +
|
|
|
|
include/uapi/linux/input.h | 1 +
|
2020-04-02 22:23:37 +00:00
|
|
|
37 files changed, 1735 insertions(+)
|
2020-01-28 22:40:18 +00:00
|
|
|
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
|
2020-03-17 01:16:47 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/data.c
|
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/data.h
|
2020-01-28 22:40:18 +00:00
|
|
|
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
|
2020-03-17 01:16:47 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/payload.c
|
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/payload.h
|
2020-01-28 22:40:18 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/commands.h
|
2020-03-17 01:16:47 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/data.h
|
2020-01-28 22:40:18 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/events.h
|
2020-03-17 01:16:47 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/feedback.h
|
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/payload.h
|
2020-01-28 22:40:18 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/responses.h
|
2020-03-17 01:16:47 +00:00
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/singletouch.h
|
|
|
|
create mode 100644 drivers/input/touchscreen/ipts/protocol/stylus.h
|
2020-01-28 22:40:18 +00:00
|
|
|
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 c071f7c407b6..028ff55d779d 100644
|
|
|
|
--- a/drivers/input/touchscreen/Kconfig
|
|
|
|
+++ b/drivers/input/touchscreen/Kconfig
|
|
|
|
@@ -1310,4 +1310,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 94c6162409b3..864f0e092ab6 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 000000000000..d3c530dafa94
|
|
|
|
--- /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
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..0f7c904e7317
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/Makefile
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,17 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+#
|
|
|
|
+# Makefile for the IPTS touchscreen driver
|
|
|
|
+#
|
|
|
|
+
|
|
|
|
+obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts.o
|
|
|
|
+ipts-objs := control.o
|
2020-03-17 01:16:47 +00:00
|
|
|
+ipts-objs += data.o
|
2020-01-28 22:40:18 +00:00
|
|
|
+ipts-objs += hid.o
|
|
|
|
+ipts-objs += init.o
|
|
|
|
+ipts-objs += math.o
|
|
|
|
+ipts-objs += params.o
|
2020-03-17 01:16:47 +00:00
|
|
|
+ipts-objs += payload.o
|
2020-01-28 22:40:18 +00:00
|
|
|
+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
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..13ea03b6482e
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/context.h
|
|
|
|
@@ -0,0 +1,61 @@
|
|
|
|
+/* 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>
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/commands.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+#include "protocol/responses.h"
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+/* HACK: Workaround for DKMS build without BUS_MEI patch */
|
|
|
|
+#ifndef BUS_MEI
|
|
|
|
+#define BUS_MEI 0x44
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+/* IPTS driver states */
|
2020-01-28 22:40:18 +00:00
|
|
|
+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;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ struct ipts_buffer_info data[16];
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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;
|
2020-03-17 01:16:47 +00:00
|
|
|
+ struct task_struct *data_loop;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ struct input_dev *stylus;
|
|
|
|
+ struct input_dev *singletouch;
|
|
|
|
+ u16 stylus_tool;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#endif /* _IPTS_CONTEXT_H_ */
|
|
|
|
diff --git a/drivers/input/touchscreen/ipts/control.c b/drivers/input/touchscreen/ipts/control.c
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..9179eca66558
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/control.c
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,94 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+
|
|
|
|
+#include <linux/mei_cl_bus.h>
|
|
|
|
+#include <linux/types.h>
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+#include "params.h"
|
|
|
|
+#include "protocol/commands.h"
|
|
|
|
+#include "protocol/events.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/feedback.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+#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;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts_data_free(ipts);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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 000000000000..e57609c85d62
|
|
|
|
--- /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_ */
|
2020-03-17 01:16:47 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/data.c b/drivers/input/touchscreen/ipts/data.c
|
2020-01-28 22:40:18 +00:00
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..568bf04f7ea6
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
2020-03-17 01:16:47 +00:00
|
|
|
+++ b/drivers/input/touchscreen/ipts/data.c
|
|
|
|
@@ -0,0 +1,107 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+// 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"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "payload.h"
|
|
|
|
+#include "protocol/data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static void ipts_data_handle_input(struct ipts_context *ipts, int buffer_id)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
|
|
|
+ struct ipts_buffer_info buffer;
|
2020-03-17 01:16:47 +00:00
|
|
|
+ struct ipts_data *data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ buffer = ipts->data[buffer_id];
|
|
|
|
+ data = (struct ipts_data *)buffer.address;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ switch (data->type) {
|
|
|
|
+ case IPTS_DATA_TYPE_PAYLOAD:
|
|
|
|
+ ipts_payload_handle_input(ipts, data);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ break;
|
2020-03-17 01:16:47 +00:00
|
|
|
+ case IPTS_DATA_TYPE_HID_REPORT:
|
|
|
|
+ ipts_hid_handle_input(ipts, data);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ break;
|
2020-03-17 01:16:47 +00:00
|
|
|
+ default:
|
2020-01-28 22:40:18 +00:00
|
|
|
+ // ignore
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ipts_control_send_feedback(ipts, buffer_id, data->transaction);
|
|
|
|
+}
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+int ipts_data_loop(void *data)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
2020-03-17 01:16:47 +00:00
|
|
|
+ time64_t timeout;
|
|
|
|
+ u32 doorbell;
|
|
|
|
+ u32 last_doorbell;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ struct ipts_context *ipts;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ timeout = ktime_get_seconds() + 5;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ ipts = (struct ipts_context *)data;
|
|
|
|
+ last_doorbell = 0;
|
|
|
|
+ doorbell = 0;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ dev_info(ipts->dev, "Starting data loop\n");
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ while (!kthread_should_stop()) {
|
|
|
|
+ if (ipts->status != IPTS_HOST_STATUS_STARTED) {
|
|
|
|
+ msleep(1000);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ // 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.
|
2020-01-28 22:40:18 +00:00
|
|
|
+ doorbell = *(u32 *)ipts->doorbell.address;
|
|
|
|
+ if (doorbell == last_doorbell)
|
|
|
|
+ goto sleep;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ timeout = ktime_get_seconds() + 5;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ while (last_doorbell != doorbell) {
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts_data_handle_input(ipts, last_doorbell % 16);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ last_doorbell++;
|
|
|
|
+ }
|
|
|
|
+sleep:
|
2020-03-17 01:16:47 +00:00
|
|
|
+ if (timeout > ktime_get_seconds())
|
2020-01-28 22:40:18 +00:00
|
|
|
+ usleep_range(5000, 30000);
|
|
|
|
+ else
|
|
|
|
+ msleep(200);
|
|
|
|
+ }
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ dev_info(ipts->dev, "Stopping data loop\n");
|
2020-01-28 22:40:18 +00:00
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+int ipts_data_init(struct ipts_context *ipts)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ret = ipts_payload_init(ipts);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ 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 000000000000..fa72c1be0945
|
|
|
|
--- /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 000000000000..2642990b8c42
|
|
|
|
--- /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;
|
|
|
|
+
|
2020-01-28 22:40:18 +00:00
|
|
|
+ ret = ipts_singletouch_init(ipts);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
2020-03-17 01:16:47 +00:00
|
|
|
+
|
|
|
|
+void ipts_hid_free(struct ipts_context *ipts)
|
|
|
|
+{
|
|
|
|
+ ipts_singletouch_free(ipts);
|
|
|
|
+}
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/hid.h b/drivers/input/touchscreen/ipts/hid.h
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..e6cf38fce454
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/hid.h
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,13 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
+
|
|
|
|
+#ifndef _IPTS_HID_H_
|
|
|
|
+#define _IPTS_HID_H_
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+int ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data);
|
2020-01-28 22:40:18 +00:00
|
|
|
+int ipts_hid_init(struct ipts_context *ipts);
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_hid_free(struct ipts_context *ipts);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+#endif /* _IPTS_HID_H_ */
|
|
|
|
diff --git a/drivers/input/touchscreen/ipts/init.c b/drivers/input/touchscreen/ipts/init.c
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..fb70d55542af
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /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"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+#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");
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts->data_loop = kthread_run(ipts_data_loop, (void *)ipts,
|
|
|
|
+ "ipts_data_loop");
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ 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);
|
2020-03-17 01:16:47 +00:00
|
|
|
+ kthread_stop(ipts->data_loop);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ 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 000000000000..df956e5447e0
|
|
|
|
--- /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 000000000000..8e831074ab60
|
|
|
|
--- /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 000000000000..6aa3f5cf1d76
|
|
|
|
--- /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 000000000000..1f992a3bc21b
|
|
|
|
--- /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_ */
|
2020-03-17 01:16:47 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/payload.c b/drivers/input/touchscreen/ipts/payload.c
|
|
|
|
new file mode 100644
|
|
|
|
index 000000000000..3572ddc0f2fb
|
|
|
|
--- /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 000000000000..6603714bb6fd
|
|
|
|
--- /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_ */
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/commands.h b/drivers/input/touchscreen/ipts/protocol/commands.h
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..2533dfb13584
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/protocol/commands.h
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,61 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* 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>
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+enum ipts_sensor_mode {
|
|
|
|
+ IPTS_SENSOR_MODE_SINGLETOUCH = 0,
|
|
|
|
+ IPTS_SENSOR_MODE_MULTITOUCH,
|
|
|
|
+ IPTS_SENSOR_MODE_MAX
|
|
|
|
+};
|
|
|
|
+
|
2020-01-28 22:40:18 +00:00
|
|
|
+struct ipts_set_mode_cmd {
|
|
|
|
+ u32 sensor_mode;
|
|
|
|
+ u8 reserved[12];
|
|
|
|
+} __packed;
|
|
|
|
+
|
|
|
|
+struct ipts_set_mem_window_cmd {
|
2020-03-17 01:16:47 +00:00
|
|
|
+ u32 data_buffer_addr_lower[16];
|
|
|
|
+ u32 data_buffer_addr_upper[16];
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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_ */
|
2020-03-17 01:16:47 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/data.h b/drivers/input/touchscreen/ipts/protocol/data.h
|
2020-01-28 22:40:18 +00:00
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..148e0545b2e4
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
2020-03-17 01:16:47 +00:00
|
|
|
+++ b/drivers/input/touchscreen/ipts/protocol/data.h
|
|
|
|
@@ -0,0 +1,30 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#ifndef _IPTS_PROTOCOL_DATA_H_
|
|
|
|
+#define _IPTS_PROTOCOL_DATA_H_
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include <linux/build_bug.h>
|
|
|
|
+#include <linux/types.h>
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+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
|
2020-01-28 22:40:18 +00:00
|
|
|
+};
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+struct ipts_data {
|
|
|
|
+ u32 type;
|
|
|
|
+ u32 size;
|
|
|
|
+ u32 buffer;
|
|
|
|
+ u8 reserved1[20];
|
|
|
|
+ u8 transaction;
|
|
|
|
+ u8 reserved2[31];
|
|
|
|
+ u8 data[];
|
|
|
|
+} __packed;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static_assert(sizeof(struct ipts_data) == 64);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#endif /* _IPTS_PROTOCOL_DATA_H_ */
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/events.h b/drivers/input/touchscreen/ipts/protocol/events.h
|
|
|
|
new file mode 100644
|
|
|
|
index 000000000000..f8b771f90bd2
|
|
|
|
--- /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_ */
|
2020-03-17 01:16:47 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/feedback.h b/drivers/input/touchscreen/ipts/protocol/feedback.h
|
|
|
|
new file mode 100644
|
|
|
|
index 000000000000..8b3d8b689ee8
|
|
|
|
--- /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 000000000000..f46da4ea81f2
|
|
|
|
--- /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_ */
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/responses.h b/drivers/input/touchscreen/ipts/protocol/responses.h
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..27153d82a5d6
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/protocol/responses.h
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,62 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* 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>
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+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
|
|
|
|
+};
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+struct ipts_device_info {
|
|
|
|
+ u16 vendor_id;
|
|
|
|
+ u16 device_id;
|
|
|
|
+ u32 hw_rev;
|
|
|
|
+ u32 fw_rev;
|
|
|
|
+
|
|
|
|
+ /* Required size of one touch data buffer */
|
2020-03-17 01:16:47 +00:00
|
|
|
+ u32 data_size;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ /* 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_ */
|
2020-03-17 01:16:47 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/protocol/singletouch.h b/drivers/input/touchscreen/ipts/protocol/singletouch.h
|
2020-01-28 22:40:18 +00:00
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..bf9912ee2af4
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
2020-03-17 01:16:47 +00:00
|
|
|
+++ b/drivers/input/touchscreen/ipts/protocol/singletouch.h
|
|
|
|
@@ -0,0 +1,17 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#ifndef _IPTS_PROTOCOL_SINGLETOUCH_H_
|
|
|
|
+#define _IPTS_PROTOCOL_SINGLETOUCH_H_
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include <linux/build_bug.h>
|
2020-01-28 22:40:18 +00:00
|
|
|
+#include <linux/types.h>
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+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
|
2020-04-02 22:23:37 +00:00
|
|
|
index 000000000000..950850b365df
|
2020-03-17 01:16:47 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/protocol/stylus.h
|
2020-04-02 22:23:37 +00:00
|
|
|
@@ -0,0 +1,52 @@
|
2020-03-17 01:16:47 +00:00
|
|
|
+/* 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];
|
2020-01-28 22:40:18 +00:00
|
|
|
+ u8 data[];
|
|
|
|
+} __packed;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+struct ipts_stylus_report_serial {
|
|
|
|
+ u8 reports;
|
|
|
|
+ u8 reserved[3];
|
|
|
|
+ u32 serial;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ u8 data[];
|
|
|
|
+} __packed;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+struct ipts_stylus_report_data {
|
2020-01-28 22:40:18 +00:00
|
|
|
+ u16 timestamp;
|
|
|
|
+ u16 mode;
|
|
|
|
+ u16 x;
|
|
|
|
+ u16 y;
|
|
|
|
+ u16 pressure;
|
|
|
|
+ u16 altitude;
|
|
|
|
+ u16 azimuth;
|
|
|
|
+ u16 reserved;
|
|
|
|
+} __packed;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+struct ipts_stylus_report_data_no_tilt {
|
2020-04-02 22:23:37 +00:00
|
|
|
+ u8 reserved[4];
|
2020-01-28 22:40:18 +00:00
|
|
|
+ u8 mode;
|
|
|
|
+ u16 x;
|
|
|
|
+ u16 y;
|
|
|
|
+ u16 pressure;
|
2020-04-02 22:23:37 +00:00
|
|
|
+ u8 reserved2;
|
2020-01-28 22:40:18 +00:00
|
|
|
+} __packed;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#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)
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+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);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+#endif /* _IPTS_PAYLOAD_STYLUS_H_ */
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/receiver.c b/drivers/input/touchscreen/ipts/receiver.c
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..ab283994c3e5
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/receiver.c
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,265 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+
|
|
|
|
+#include <linux/types.h>
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
|
|
|
+#include "control.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+#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);
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ if (ipts_data_init(ipts))
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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++) {
|
2020-03-17 01:16:47 +00:00
|
|
|
+ cmd.data_buffer_addr_lower[i] =
|
|
|
|
+ lower_32_bits(ipts->data[i].dma_address);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ cmd.data_buffer_addr_upper[i] =
|
|
|
|
+ upper_32_bits(ipts->data[i].dma_address);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ 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);
|
2020-03-17 01:16:47 +00:00
|
|
|
+ cmd.host2me_size = ipts->device_info.data_size;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ if (ipts->status == IPTS_HOST_STATUS_STOPPING)
|
|
|
|
+ return 0;
|
|
|
|
+
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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 000000000000..4d413a0abd4c
|
|
|
|
--- /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
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..704db9fdd3fd
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /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;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ touch_buffer_size = ipts->device_info.data_size;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ feedback_buffer_size = ipts->device_info.feedback_size;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ buffers = ipts->data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ touch_buffer_size = ipts->device_info.data_size;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ feedback_buffer_size = ipts->device_info.feedback_size;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ buffers = ipts->data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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 000000000000..cf9807b0dbe6
|
|
|
|
--- /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
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..ed70444f649c
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/singletouch.c
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,64 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+
|
|
|
|
+#include <linux/input.h>
|
|
|
|
+#include <linux/kernel.h>
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/data.h"
|
|
|
|
+#include "protocol/singletouch.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_singletouch_handle_input(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_data *data)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
|
|
|
+ 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;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts->singletouch = input_allocate_device();
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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";
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts->singletouch->name = "IPTS Singletouch";
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ ret = input_register_device(ipts->singletouch);
|
|
|
|
+ if (ret) {
|
2020-03-17 01:16:47 +00:00
|
|
|
+ dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
|
|
|
|
+ ipts->singletouch->name, ret);
|
|
|
|
+ input_free_device(ipts->singletouch);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
2020-03-17 01:16:47 +00:00
|
|
|
+
|
|
|
|
+void ipts_singletouch_free(struct ipts_context *ipts)
|
|
|
|
+{
|
|
|
|
+ if (!ipts->singletouch)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ input_unregister_device(ipts->singletouch);
|
|
|
|
+}
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/singletouch.h b/drivers/input/touchscreen/ipts/singletouch.h
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..53207497a462
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/singletouch.h
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,14 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
+
|
|
|
|
+#ifndef _IPTS_SINGLETOUCH_H_
|
|
|
|
+#define _IPTS_SINGLETOUCH_H_
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/data.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_singletouch_handle_input(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_data *data);
|
2020-01-28 22:40:18 +00:00
|
|
|
+int ipts_singletouch_init(struct ipts_context *ipts);
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_singletouch_free(struct ipts_context *ipts);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+#endif /* _IPTS_SINGLETOUCH_H_ */
|
|
|
|
diff --git a/drivers/input/touchscreen/ipts/stylus.c b/drivers/input/touchscreen/ipts/stylus.c
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..dbb4fe0bf559
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/stylus.c
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,191 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
+
|
|
|
|
+#include <linux/input.h>
|
|
|
|
+#include <linux/kernel.h>
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
|
|
|
+#include "math.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/payload.h"
|
|
|
|
+#include "protocol/stylus.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static void ipts_stylus_handle_stylus_data(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_stylus_report_data *data)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
|
|
|
+ u16 tool;
|
2020-03-17 01:16:47 +00:00
|
|
|
+ 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;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ s32 tx = 0;
|
|
|
|
+ s32 ty = 0;
|
|
|
|
+
|
|
|
|
+ // avoid unnecessary computations
|
|
|
|
+ // altitude is zero if stylus does not touch the screen
|
2020-03-17 01:16:47 +00:00
|
|
|
+ if (data->altitude) {
|
|
|
|
+ ipts_math_altitude_azimuth_to_tilt(data->altitude,
|
|
|
|
+ data->azimuth, &tx, &ty);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (prox && rubber)
|
|
|
|
+ tool = BTN_TOOL_RUBBER;
|
|
|
|
+ else
|
|
|
|
+ tool = BTN_TOOL_PEN;
|
|
|
|
+
|
|
|
|
+ // Fake proximity out to switch tools
|
|
|
|
+ if (ipts->stylus_tool != tool) {
|
|
|
|
+ input_report_key(ipts->stylus, ipts->stylus_tool, 0);
|
|
|
|
+ input_sync(ipts->stylus);
|
|
|
|
+ ipts->stylus_tool = tool;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ input_report_key(ipts->stylus, BTN_TOUCH, touch);
|
|
|
|
+ input_report_key(ipts->stylus, ipts->stylus_tool, prox);
|
|
|
|
+ input_report_key(ipts->stylus, BTN_STYLUS, button);
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ 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);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ input_report_abs(ipts->stylus, ABS_TILT_X, tx);
|
|
|
|
+ input_report_abs(ipts->stylus, ABS_TILT_Y, ty);
|
|
|
|
+
|
|
|
|
+ input_sync(ipts->stylus);
|
|
|
|
+}
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static void ipts_stylus_handle_report_tilt_serial(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_report *report)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
2020-03-17 01:16:47 +00:00
|
|
|
+ int i;
|
|
|
|
+ struct ipts_stylus_report_serial *stylus_report;
|
|
|
|
+ struct ipts_stylus_report_data *data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ stylus_report = (struct ipts_stylus_report_serial *)report->data;
|
|
|
|
+ data = (struct ipts_stylus_report_data *)stylus_report->data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ // TODO: Track serial number and support multiple styli
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ for (i = 0; i < stylus_report->reports; i++)
|
|
|
|
+ ipts_stylus_handle_stylus_data(ipts, &data[i]);
|
2020-01-28 22:40:18 +00:00
|
|
|
+}
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static void ipts_stylus_handle_report_tilt(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_report *report)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
2020-03-17 01:16:47 +00:00
|
|
|
+ int i;
|
|
|
|
+ struct ipts_stylus_report *stylus_report;
|
|
|
|
+ struct ipts_stylus_report_data *data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ stylus_report = (struct ipts_stylus_report *)report->data;
|
|
|
|
+ data = (struct ipts_stylus_report_data *)stylus_report->data;
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ for (i = 0; i < stylus_report->reports; i++)
|
|
|
|
+ ipts_stylus_handle_stylus_data(ipts, &data[i]);
|
2020-01-28 22:40:18 +00:00
|
|
|
+}
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+static void ipts_stylus_handle_report_no_tilt(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_report *report)
|
2020-01-28 22:40:18 +00:00
|
|
|
+{
|
2020-03-17 01:16:47 +00:00
|
|
|
+ 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;
|
|
|
|
+ }
|
2020-01-28 22:40:18 +00:00
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int ipts_stylus_init(struct ipts_context *ipts)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts->stylus = input_allocate_device();
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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);
|
2020-03-17 01:16:47 +00:00
|
|
|
+ input_set_abs_params(ipts->stylus, ABS_PRESSURE, 0, 4096, 0, 0);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ 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";
|
2020-03-17 01:16:47 +00:00
|
|
|
+ ipts->stylus->name = "IPTS Stylus";
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+ ret = input_register_device(ipts->stylus);
|
|
|
|
+ if (ret) {
|
2020-03-17 01:16:47 +00:00
|
|
|
+ dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
|
|
|
|
+ ipts->stylus->name, ret);
|
|
|
|
+ input_free_device(ipts->stylus);
|
2020-01-28 22:40:18 +00:00
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
2020-03-17 01:16:47 +00:00
|
|
|
+
|
|
|
|
+void ipts_stylus_free(struct ipts_context *ipts)
|
|
|
|
+{
|
|
|
|
+ if (!ipts->stylus)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ input_unregister_device(ipts->stylus);
|
|
|
|
+}
|
2020-01-28 22:40:18 +00:00
|
|
|
diff --git a/drivers/input/touchscreen/ipts/stylus.h b/drivers/input/touchscreen/ipts/stylus.h
|
|
|
|
new file mode 100644
|
2020-03-17 01:16:47 +00:00
|
|
|
index 000000000000..5b93add1eac2
|
2020-01-28 22:40:18 +00:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/drivers/input/touchscreen/ipts/stylus.h
|
2020-03-17 01:16:47 +00:00
|
|
|
@@ -0,0 +1,14 @@
|
2020-01-28 22:40:18 +00:00
|
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
+
|
|
|
|
+#ifndef _IPTS_STYLUS_H_
|
|
|
|
+#define _IPTS_STYLUS_H_
|
|
|
|
+
|
|
|
|
+#include "context.h"
|
2020-03-17 01:16:47 +00:00
|
|
|
+#include "protocol/payload.h"
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_stylus_handle_input(struct ipts_context *ipts,
|
|
|
|
+ struct ipts_payload_frame *frame);
|
2020-01-28 22:40:18 +00:00
|
|
|
+int ipts_stylus_init(struct ipts_context *ipts);
|
2020-03-17 01:16:47 +00:00
|
|
|
+void ipts_stylus_free(struct ipts_context *ipts);
|
2020-01-28 22:40:18 +00:00
|
|
|
+
|
|
|
|
+#endif /* _IPTS_STYLUS_H_ */
|
|
|
|
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
|
2020-02-17 14:40:12 +00:00
|
|
|
index 87a0201ba6b3..3cf5922e8c64 100644
|
2020-01-28 22:40:18 +00:00
|
|
|
--- 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 */
|
|
|
|
|
2020-02-17 14:40:12 +00:00
|
|
|
@@ -88,6 +89,7 @@
|
|
|
|
#define MEI_DEV_ID_CMP_H_3 0x06e4 /* Comet Lake H 3 (iTouch) */
|
2020-01-28 22:40:18 +00:00
|
|
|
|
|
|
|
#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) */
|
|
|
|
|
2020-02-17 14:40:12 +00:00
|
|
|
#define MEI_DEV_ID_JSP_N 0x4DE0 /* Jasper Lake Point N */
|
2020-01-28 22:40:18 +00:00
|
|
|
|
|
|
|
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
|
2020-02-17 14:40:12 +00:00
|
|
|
index 2711451b3d87..00d1eaa03dc7 100644
|
2020-01-28 22:40:18 +00:00
|
|
|
--- 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)},
|
2020-02-17 14:40:12 +00:00
|
|
|
@@ -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)},
|
2020-01-28 22:40:18 +00:00
|
|
|
|
|
|
|
{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_PCH15_CFG)},
|
|
|
|
|
|
|
|
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
|
|
|
|
index 9a61c28ed3ae..47fc20975245 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
|
|
|
|
--
|
2020-04-02 22:23:37 +00:00
|
|
|
2.26.0
|
2020-01-28 22:40:18 +00:00
|
|
|
|