Snap for 11568587 from 778537090882266a530b7d79e54eaf8e6cd4df44 to android13-msm-pixelwatch-5.15-p11-release

Change-Id: I22e1cc0b49cf2f7e1d86313930d23a4c2fc56ca8
Signed-off-by: Coastguard Worker <android-build-coastguard-worker@google.com>
diff --git a/tma525c/Kbuild b/tma525c/Kbuild
index 5988ebe..9841bb0 100644
--- a/tma525c/Kbuild
+++ b/tma525c/Kbuild
@@ -3,7 +3,7 @@
 #
 
 obj-$(CONFIG_TOUCHSCREEN_PARADE)      += pt.o
-pt-y := pt_core.o pt_mt_common.o
+pt-y := pt_core.o pt_mt_common.o mcu_touch.o
 pt-$(CONFIG_TOUCHSCREEN_PARADE_MT_A) += pt_mta.o
 pt-$(CONFIG_TOUCHSCREEN_PARADE_MT_B) += pt_mtb.o
 pt-$(CONFIG_TOUCHSCREEN_PARADE_BUTTON) += pt_btn.o
diff --git a/tma525c/Makefile b/tma525c/Makefile
index 53a2785..e2dfa06 100644
--- a/tma525c/Makefile
+++ b/tma525c/Makefile
@@ -2,10 +2,14 @@
 #
 # Makefile for the touchscreen drivers.
 #
+EXTRA_INCLUDE ?= -I$(KERNEL_SRC)/../google-modules/nanohub/
+EXTRA_SYMBOLS ?= $(OUT_DIR)/../google-modules/nanohub/Module.symvers
 
 default: all
 
-KBUILD_OPTIONS := CONFIG_TOUCHSCREEN_PARADE=m
+KBUILD_OPTIONS := CONFIG_TOUCHSCREEN_PARADE=m \
+ 		  ccflags-y=$(EXTRA_INCLUDE) \
+		  KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)"
 KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_PARADE_MT_B=y
 KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_PARADE_DEVICETREE_SUPPORT=m
 KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_PARADE_I2C=m
diff --git a/tma525c/mcu_touch.c b/tma525c/mcu_touch.c
new file mode 100644
index 0000000..6e91e16
--- /dev/null
+++ b/tma525c/mcu_touch.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2024 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include "nanohub_exports.h"
+#include "mcu_touch.h"
+#include <asm-generic/errno.h>
+
+#define NANOHUB_TOUCH_COMMAND_VERSION		     0x01
+#define NANOHUB_TOUCH_MESSAGE_SIZE		     3
+#define NANOHUB_TOUCH_MESSAGE_COMMAND_VERSION_OFFSET 0
+#define NANOHUB_TOUCH_MESSAGE_COMMAND_TYPE_OFFSET    1
+#define NANOHUB_TOUCH_MESSAGE_DISPLAY_MODE_OFFSET    2
+
+struct nanohub_touch_callback {
+	void (*on_message_received)(const struct touch_callback_data *data);
+	struct list_head list;
+};
+
+struct nanohub_touch_host {
+	struct mutex nanohub_touch_mutex;
+	bool initialized;
+	struct list_head touch_callbacks[NANOHUB_TOUCH_COMMAND_TYPE_MAX];
+};
+
+static struct nanohub_touch_host touch_host = {
+	.nanohub_touch_mutex = __MUTEX_INITIALIZER(touch_host.nanohub_touch_mutex),
+};
+
+static void parse_callback_data(struct touch_callback_data *callback_data, const char *buffer,
+				size_t length)
+{
+	uint8_t command_type;
+
+	if (length != NANOHUB_TOUCH_MESSAGE_SIZE) {
+		pr_err("nanohub: the size of touch message from MCU is not matched");
+		return;
+	}
+
+	command_type = buffer[NANOHUB_TOUCH_MESSAGE_COMMAND_TYPE_OFFSET];
+
+	switch (command_type) {
+	case NANOHUB_TOUCH_COMMAND_LISTEN_ON_DISPLAY_STATE:
+		callback_data->display_mode = buffer[NANOHUB_TOUCH_MESSAGE_DISPLAY_MODE_OFFSET];
+		break;
+	default:
+		break;
+	}
+}
+
+static void dispatcher(const char *buffer, size_t length)
+{
+	uint8_t command_type;
+	struct nanohub_touch_callback *touch_callback;
+	struct touch_callback_data callback_data;
+
+	pr_info("nanohub : touch host receive message from mcu\n");
+	mutex_lock(&touch_host.nanohub_touch_mutex);
+	if (length == NANOHUB_TOUCH_MESSAGE_SIZE &&
+	    buffer[NANOHUB_TOUCH_MESSAGE_COMMAND_VERSION_OFFSET] == NANOHUB_TOUCH_COMMAND_VERSION) {
+		command_type = buffer[NANOHUB_TOUCH_MESSAGE_COMMAND_TYPE_OFFSET];
+		parse_callback_data(&callback_data, buffer, length);
+		list_for_each_entry(touch_callback, &touch_host.touch_callbacks[command_type],
+				    list) {
+			touch_callback->on_message_received(&callback_data);
+		}
+	}
+	mutex_unlock(&touch_host.nanohub_touch_mutex);
+}
+
+static struct nanohub_touch_callback *
+callback_is_existed_locked(void (*on_message_received)(const struct touch_callback_data *data),
+			   uint32_t nanohub_touch_command_type)
+{
+	struct nanohub_touch_callback *touch_callback;
+
+	list_for_each_entry(touch_callback, &touch_host.touch_callbacks[nanohub_touch_command_type],
+			    list) {
+		if (touch_callback->on_message_received == on_message_received)
+			return touch_callback;
+	}
+	return NULL;
+}
+
+static int add_callback_locked(void (*on_message_received)(const struct touch_callback_data *data),
+			       uint32_t nanohub_touch_command_type)
+{
+	struct nanohub_touch_callback *touch_callback;
+
+	if (on_message_received == NULL) {
+		pr_err("nanohub: trying to register an NULL callback on command type:%u\n",
+		       nanohub_touch_command_type);
+		return -EPERM;
+	}
+
+	if (callback_is_existed_locked(on_message_received, nanohub_touch_command_type)) {
+		pr_err("nanohub: the callback is already existed on command type:%u\n");
+		return -EPERM;
+	}
+
+	touch_callback = kmalloc(sizeof(struct nanohub_touch_callback), GFP_KERNEL);
+	if (touch_callback == NULL) {
+		pr_err("nanohub: failed to allocate memory on command type:%u\n",
+		       nanohub_touch_command_type);
+		return -ENOMEM;
+	}
+	touch_callback->on_message_received = on_message_received;
+	list_add(&touch_callback->list, &touch_host.touch_callbacks[nanohub_touch_command_type]);
+	pr_info("nanohub : touch callback is being registered on command type:%u\n",
+		nanohub_touch_command_type);
+	return 0;
+}
+
+static int
+remove_callback_locked(void (*on_message_received)(const struct touch_callback_data *data),
+		       uint32_t nanohub_touch_command_type)
+{
+	struct nanohub_touch_callback *touch_callback;
+
+	touch_callback =
+		callback_is_existed_locked(on_message_received, nanohub_touch_command_type);
+	if (!touch_callback) {
+		pr_err("nanohub: the callback is not existed on command type:%u\n");
+		return -EINVAL;
+	}
+
+	pr_info("nanohub : touch callback is being unregistered from command type:%u\n",
+		nanohub_touch_command_type);
+	list_del(&touch_callback->list);
+	kfree(touch_callback);
+	return 0;
+}
+
+static void touch_host_initialize_locked(void)
+{
+	uint32_t command_type;
+
+	pr_info("nanohub: initializing touch host\n");
+	for (command_type = 0; command_type < NANOHUB_TOUCH_COMMAND_TYPE_MAX; command_type++)
+		INIT_LIST_HEAD(&touch_host.touch_callbacks[command_type]);
+	nanohub_register_listener(NANOHUB_TOUCH_KERNEL_CHANNEL_ID, dispatcher);
+	touch_host.initialized = true;
+}
+
+void nanohub_touch_register_listener(
+	void (*on_message_received)(const struct touch_callback_data *data),
+	uint32_t nanohub_touch_command_type)
+{
+	int rc;
+
+	mutex_lock(&touch_host.nanohub_touch_mutex);
+	if (!touch_host.initialized)
+		touch_host_initialize_locked();
+
+	rc = add_callback_locked(on_message_received, nanohub_touch_command_type);
+	mutex_unlock(&touch_host.nanohub_touch_mutex);
+	if (rc)
+		pr_err("nanohub: Failed to register listener on command type:%u, rc=%d\n",
+		       nanohub_touch_command_type, rc);
+}
+EXPORT_SYMBOL(nanohub_touch_register_listener);
+
+void nanohub_touch_unregister_listener(
+	void (*on_message_received)(const struct touch_callback_data *data),
+	uint32_t nanohub_touch_command_type)
+{
+	int rc;
+
+	if (on_message_received == NULL) {
+		pr_err("nanohub: trying to unregister an NULL callback on command type:%u\n",
+		       nanohub_touch_command_type);
+		return;
+	}
+	mutex_lock(&touch_host.nanohub_touch_mutex);
+	rc = remove_callback_locked(on_message_received, nanohub_touch_command_type);
+	mutex_unlock(&touch_host.nanohub_touch_mutex);
+	if (rc)
+		pr_err("nanohub: Failed to unregister listener on command type:%u, rc=%d\n",
+		       nanohub_touch_command_type, rc);
+}
+EXPORT_SYMBOL(nanohub_touch_unregister_listener);
diff --git a/tma525c/mcu_touch.h b/tma525c/mcu_touch.h
new file mode 100644
index 0000000..72d1a7b
--- /dev/null
+++ b/tma525c/mcu_touch.h
@@ -0,0 +1,30 @@
+#ifndef _MCU_TOUCH_H
+#define _MCU_TOUCH_H
+
+/* Commands type should be aligned with MCU*/
+enum nanohub_touch_command_type {
+	NANOHUB_TOUCH_COMMAND_LISTEN_ON_DISPLAY_STATE,
+	NANOHUB_TOUCH_COMMAND_TYPE_MAX,
+};
+
+// Wrapper structure for callback register
+struct touch_callback_data {
+	union {
+		char display_mode; // NANOHUB_TOUCH_COMMAND_LISTEN_ON_DISPLAY_STATE
+	};
+};
+/*
+ * Register a callback from MCU touch service,
+ * the callback will be triggered when there's a corresponding command type sent from MCU.
+ */
+extern void
+nanohub_touch_register_listener(void (*on_message_received)(const struct touch_callback_data *data),
+				uint32_t nanohub_touch_command_type);
+
+/*
+ * Unregister the callback from nanohub_touch_unregister_listenr().
+ */
+extern void nanohub_touch_unregister_listener(
+	void (*on_message_received)(const struct touch_callback_data *data),
+	uint32_t nanohub_touch_command_type);
+#endif
diff --git a/tma525c/pt_core.c b/tma525c/pt_core.c
index 42478ab..96f220c 100644
--- a/tma525c/pt_core.c
+++ b/tma525c/pt_core.c
@@ -32,6 +32,9 @@
 #include <linux/kthread.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/input/mt.h>
+#include "nanohub_exports.h"
+#include "mcu_touch.h"
 
 #ifdef PT_PTSBC_SUPPORT
 #define PT_CORE_PROBE_STARTUP_DELAY_MS 500
@@ -44,6 +47,7 @@
 static const char *pt_driver_core_name = PT_CORE_NAME;
 static const char *pt_driver_core_version = PT_DRIVER_VERSION;
 static const char *pt_driver_core_date = PT_DRIVER_DATE;
+struct pt_input_event touch_event_list_head;
 
 struct pt_hid_field {
 	int report_count;
@@ -187,6 +191,17 @@
 	 ((id) == PT_HID_WRAP_PIP_REPORT_ID)
 
 #define PT_MAX_PR_BUF_SIZE  2048
+
+void queue_input_event(uint16_t type, uint16_t code, int32_t value, ktime_t timestamp)
+{
+	struct pt_input_event *input_report_event =
+		kmalloc(sizeof(struct pt_input_event), GFP_KERNEL);
+	input_report_event->type = type;
+	input_report_event->code = code;
+	input_report_event->value = value;
+	input_report_event->timestamp = timestamp;
+	list_add_tail(&input_report_event->list, &touch_event_list_head.list);
+}
 /*******************************************************************************
  * FUNCTION: pt_pr_buf
  *
@@ -10355,6 +10370,9 @@
 	cancel_work_sync(&cd->enum_work);
 	pt_stop_wd_timer(cd);
 
+	// Ensure device is awake to send i2c command
+	pm_stay_awake(cd->dev);
+
 	if (IS_EASY_WAKE_CONFIGURED(cd->easy_wakeup_gesture))
 		rc = pt_put_device_into_easy_wakeup_(cd);
 	else if (cd->cpdata->flags & PT_CORE_FLAG_POWEROFF_ON_SLEEP)
@@ -10364,6 +10382,8 @@
 	else
 		rc = pt_put_device_into_deep_sleep_(cd);
 
+	pm_relax(cd->dev);
+
 	mutex_lock(&cd->system_lock);
 	if (rc == 0) {
 		cd->sleep_state = SS_SLEEP_ON;
@@ -13288,6 +13308,9 @@
 	cd->sleep_state = SS_WAKING;
 	mutex_unlock(&cd->system_lock);
 
+	// Ensure device is awake to send i2c command
+	pm_stay_awake(cd->dev);
+
 	if (!(cd->cpdata->flags & PT_CORE_FLAG_SKIP_RESUME)) {
 		if (IS_EASY_WAKE_CONFIGURED(cd->easy_wakeup_gesture))
 			rc = pt_core_wake_device_from_easy_wake_(cd);
@@ -13299,6 +13322,8 @@
 			rc = pt_core_wake_device_from_deep_sleep_(cd);
 	}
 
+	pm_relax(cd->dev);
+
 	mutex_lock(&cd->system_lock);
 	if (rc == 0)
 		cd->sleep_state = SS_SLEEP_OFF;
@@ -13348,6 +13373,71 @@
 	return rc;
 }
 
+static void on_mcu_display_state_change(const struct touch_callback_data *data)
+{
+	struct pt_core_data *core_data = pt_get_core_data(PT_DEFAULT_CORE_ID);
+
+	pr_info("[pt_i2c_adapter] %s: received messages from mcu\n", __func__);
+
+	if (core_data == NULL) {
+		pr_err("[pt_i2c_adapter] %s: Core data is NULL\n", __func__);
+		return;
+	}
+
+	if (unlikely(!data)) {
+		pr_err("[pt_i2c_adapter] %s: Callback data is NULL\n", __func__);
+		return;
+	}
+
+	switch (data->display_mode) {
+	case MCU_DISPLAY_ON: {
+		mutex_lock(&core_data->md.mt_lock);
+		core_data->md.touch_state = WAKING_BY_ACTIVE_TOUCH;
+		mutex_unlock(&core_data->md.mt_lock);
+		pt_core_wake(core_data);
+		break;
+	}
+	case MCU_DISPLAY_IDLE:
+	case MCU_DISPLAY_OFF:
+	case MCU_DISPLAY_SLEEP:
+		pt_core_sleep(core_data);
+		break;
+	default:
+		pr_err("[pt_i2c_adapter] %s: no action for display_mode:%d\n", __func__,
+		       data->display_mode);
+		break;
+	}
+}
+
+void pt_release_queued_input_event(void)
+{
+	struct pt_input_event *event;
+	struct pt_input_event *next_event;
+	struct pt_core_data *core_data = pt_get_core_data(PT_DEFAULT_CORE_ID);
+
+	mutex_lock(&core_data->md.mt_lock);
+	if (core_data->md.touch_state == QUEUEING_TOUCH_EVENTS) {
+		pt_debug(core_data->dev, DL_INFO, "%s: releasing queued input events\n", __func__);
+		list_for_each_entry_safe(event, next_event, &touch_event_list_head.list, list) {
+			if (event->type == EV_SYNC_FRAME)
+				input_mt_sync_frame(core_data->md.input);
+			else if (event->type == EV_TIMESTAMP)
+				input_set_timestamp(core_data->md.input, event->timestamp);
+			else if (event->type == EV_SLOT_STATE)
+				input_mt_report_slot_state(core_data->md.input, event->code,
+							   event->value);
+			else
+				input_event(core_data->md.input, event->type, event->code,
+					    event->value);
+
+			list_del(&event->list);
+			kfree(event);
+		}
+	}
+	core_data->md.touch_state = NORMAL;
+	mutex_unlock(&core_data->md.mt_lock);
+}
+
 /*******************************************************************************
  * FUNCTION: pt_get_ic_crc_
  *
@@ -16985,6 +17075,54 @@
 }
 EXPORT_SYMBOL(pt_get_module_data);
 
+void pt_touch_display_resume(struct pt_core_data *core_data)
+{
+	if (core_data->drm_panel_state == DRM_PANEL_ON) {
+		pt_debug(core_data->dev, DL_ERROR, "%s: touch is still resume\n", __func__);
+		return;
+	}
+	core_data->drm_panel_state = DRM_PANEL_ON;
+	call_atten_cb(core_data, PT_ATTEN_RESUME, 0);
+#if defined(CONFIG_PM_SLEEP)
+	if (core_data->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME) {
+		pt_debug(core_data->dev, DL_INFO, "%s: call pt_core_resume_!\n", __func__);
+		pt_core_resume_(core_data->dev);
+	}
+#endif
+}
+
+void pt_touch_display_idle(struct pt_core_data *core_data)
+{
+	if (core_data->drm_panel_state == DRM_PANEL_LP) {
+		pt_debug(core_data->dev, DL_ERROR, "%s: touch is still idle\n", __func__);
+		return;
+	}
+	core_data->drm_panel_state = DRM_PANEL_LP;
+#if defined(CONFIG_PM_SLEEP)
+	if (core_data->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME) {
+		pt_debug(core_data->dev, DL_INFO, "%s: call pt_core_suspend_!\n", __func__);
+		pt_core_suspend_(core_data->dev);
+	}
+#endif
+	call_atten_cb(core_data, PT_ATTEN_SUSPEND, 0);
+}
+
+void pt_touch_display_suspend(struct pt_core_data *core_data)
+{
+	if (core_data->drm_panel_state == DRM_PANEL_OFF) {
+		pt_debug(core_data->dev, DL_ERROR, "%s: touch is still suspend\n", __func__);
+		return;
+	}
+	core_data->drm_panel_state = DRM_PANEL_OFF;
+#if defined(CONFIG_PM_SLEEP)
+	if (core_data->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME) {
+		pt_debug(core_data->dev, DL_INFO, "%s: call pt_core_suspend_!\n", __func__);
+		pt_core_suspend_(core_data->dev);
+	}
+#endif
+	call_atten_cb(core_data, PT_ATTEN_SUSPEND, 0);
+}
+
 #ifdef CONFIG_HAS_EARLYSUSPEND
 /*******************************************************************************
  * FUNCTION: pt_early_suspend
@@ -17131,47 +17269,19 @@
 
 	switch (notification->notif_type) {
 	case DRM_PANEL_EVENT_UNBLANK:
-		if (notification->notif_data.early_trigger) {
-			pt_debug(core_data->dev, DL_INFO, "%s: resume notification pre commit\n",
-				 __func__);
-			break;
+		if (!notification->notif_data.early_trigger) {
+			pt_release_queued_input_event();
+			pt_touch_display_resume(core_data);
 		}
-		if (core_data->drm_panel_state == DRM_PANEL_ON) {
-			pt_debug(core_data->dev, DL_INFO, "%s: touch is still resume\n", __func__);
-			break;
-		}
-
-		call_atten_cb(core_data, PT_ATTEN_RESUME, 0);
-#if defined(CONFIG_PM_SLEEP)
-		if (core_data->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME) {
-			pt_debug(core_data->dev, DL_INFO, "%s: call pt_core_resume_!\n", __func__);
-			pt_core_resume_(core_data->dev);
-		}
-#endif
-		core_data->drm_panel_state = DRM_PANEL_ON;
 		break;
 	case DRM_PANEL_EVENT_BLANK_LP:
-		pt_debug(core_data->dev, DL_INFO, "%s: received lp event\n", __func__);
-		fallthrough;
-	case DRM_PANEL_EVENT_BLANK:
-		if (core_data->drm_panel_state == DRM_PANEL_OFF) {
-			pt_debug(core_data->dev, DL_INFO, "%s: touch is still suspend\n", __func__);
-			break;
-		}
-#if defined(CONFIG_PM_SLEEP)
-		if (core_data->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME) {
-			pt_debug(core_data->dev, DL_INFO, "%s: call pt_core_suspend_!\n", __func__);
-			pt_core_suspend_(core_data->dev);
-		}
-#endif
-		call_atten_cb(core_data, PT_ATTEN_SUSPEND, 0);
-		/*
-		 * TODO (b/260792453):
-		 * Fix drm_panel_state with the issue in comment#6
-		 */
-		core_data->drm_panel_state = DRM_PANEL_OFF;
+		if (notification->notif_data.early_trigger)
+			pt_touch_display_idle(core_data);
 		break;
-
+	case DRM_PANEL_EVENT_BLANK:
+		if (notification->notif_data.early_trigger)
+			pt_touch_display_suspend(core_data);
+		break;
 	case DRM_PANEL_EVENT_FPS_CHANGE:
 		pt_debug(core_data->dev, DL_INFO, "Received fps change old fps:%d new fps:%d\n",
 			 notification->notif_data.old_fps, notification->notif_data.new_fps);
@@ -22416,6 +22526,9 @@
 	/* Initialize parameter list */
 	INIT_LIST_HEAD(&cd->param_list);
 
+	/* Initialize touch event list*/
+	INIT_LIST_HEAD(&touch_event_list_head.list);
+
 	/* Initialize wait queue */
 	init_waitqueue_head(&cd->wait_q);
 
@@ -22492,7 +22605,11 @@
 		pt_debug(cd->dev, DL_WARN, "%s:No irq_stat, Set cd->irq = %d\n",
 			__func__, cd->irq);
 	}
-
+	pt_debug(cd->dev, DL_INFO, "%s: nanohub display state change callback register\n",
+		 __func__);
+	nanohub_touch_register_listener(on_mcu_display_state_change,
+					NANOHUB_TOUCH_COMMAND_LISTEN_ON_DISPLAY_STATE);
+	pt_add_core(cd->dev);
 #ifdef PT_PTSBC_SUPPORT
 	/*
 	 * For the PtSBC, on the first bring up, I2C/SPI will not be ready
@@ -22922,7 +23039,8 @@
 #ifdef PT_PTSBC_SUPPORT
 	cancel_work_sync(&cd->irq_work);
 #endif
-
+	nanohub_touch_unregister_listener(on_mcu_display_state_change,
+					  NANOHUB_TOUCH_COMMAND_LISTEN_ON_DISPLAY_STATE);
 	pt_release_modules(cd);
 	pt_proximity_release(dev);
 	pt_btn_release(dev);
diff --git a/tma525c/pt_mt_common.c b/tma525c/pt_mt_common.c
index 8dbb0ab..91b8ae4 100644
--- a/tma525c/pt_mt_common.c
+++ b/tma525c/pt_mt_common.c
@@ -29,6 +29,9 @@
  */
 
 #include "pt_regs.h"
+#include "nanohub_exports.h"
+#include <linux/input-event-codes.h>
+#include <linux/input/mt.h>
 
 #define MT_PARAM_SIGNAL(md, sig_ost) PARAM_SIGNAL(md->pdata->frmwrk, sig_ost)
 #define MT_PARAM_MIN(md, sig_ost) PARAM_MIN(md->pdata->frmwrk, sig_ost)
@@ -36,6 +39,63 @@
 #define MT_PARAM_FUZZ(md, sig_ost) PARAM_FUZZ(md->pdata->frmwrk, sig_ost)
 #define MT_PARAM_FLAT(md, sig_ost) PARAM_FLAT(md->pdata->frmwrk, sig_ost)
 
+extern struct pt_input_event touch_event_list_head;
+extern void queue_input_event(uint16_t type, uint16_t code, int32_t value, ktime_t timestamp);
+struct mcu_input_message {
+	uint8_t type;
+	uint32_t code;
+	int32_t value;
+} __packed;
+
+static inline void assign_input_message(uint8_t type, uint32_t code, int32_t value,
+					struct mcu_input_message *input)
+{
+	if (unlikely(input == NULL))
+		return;
+
+	memcpy(&input->type, &type, sizeof(input->type));
+	memcpy(&input->code, &code, sizeof(input->code));
+	memcpy(&input->value, &value, sizeof(input->value));
+}
+
+static int pt_send_mcu_message(unsigned int type, unsigned int code, int value)
+{
+	ssize_t bytes;
+	struct mcu_input_message input;
+
+	assign_input_message(type, code, value, &input);
+
+	bytes = nanohub_send_message(NANOHUB_TOUCH_CHANNEL_ID, (const char *)&input, sizeof(input));
+	if (bytes != sizeof(input)) {
+		pr_err("MCU Bytes sent expected = %zd, actual = %zd\n", sizeof(input), bytes);
+		return -EIO;
+	}
+	return 0;
+}
+
+static inline void pt_mcu_report_key(unsigned int code, int value)
+{
+	pt_send_mcu_message(EV_KEY, code, value);
+}
+
+static inline void pt_mcu_report_abs(unsigned int code, int value)
+{
+	pt_send_mcu_message(EV_ABS, code, value);
+}
+
+static inline void pt_mcu_sync(void)
+{
+	pt_send_mcu_message(EV_SYN, SYN_REPORT, 0);
+}
+
+static void pt_mcu_send_key(uint32_t keycode)
+{
+	pt_mcu_report_key(keycode, 1);
+	pt_mcu_sync();
+	pt_mcu_report_key(keycode, 0);
+	pt_mcu_sync();
+}
+
 /*******************************************************************************
  * FUNCTION: pt_mt_lift_all
  *
@@ -51,7 +111,10 @@
 	if (md->num_prv_rec != 0) {
 		if (md->mt_function.report_slot_liftoff)
 			md->mt_function.report_slot_liftoff(md, max);
-		input_sync(md->input);
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS)
+			queue_input_event(EV_SYN, SYN_REPORT, 0, 0);
+		else
+			input_sync(md->input);
 		md->num_prv_rec = 0;
 	}
 }
@@ -216,8 +279,12 @@
 {
 	int sig = MT_PARAM_SIGNAL(md, event);
 
-	if (sig != PT_IGNORE_VALUE)
-		input_report_abs(md->input, sig, value);
+	if (sig != PT_IGNORE_VALUE) {
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS)
+			queue_input_event(EV_ABS, sig, value, 0);
+		else
+			input_report_abs(md->input, sig, value);
+	}
 }
 
 /*******************************************************************************
@@ -234,6 +301,7 @@
 		struct pt_touch *tch, int num_cur_tch)
 {
 	struct device *dev = md->dev;
+	struct pt_core_data *cd = dev_get_drvdata(dev);
 	struct pt_sysinfo *si = md->si;
 	int sig;
 	int i, j, t = 0;
@@ -290,9 +358,25 @@
 
 		sig = MT_PARAM_SIGNAL(md, PT_ABS_ID_OST);
 		if (sig != PT_IGNORE_VALUE) {
-			if (md->mt_function.input_report)
+			if (md->mt_function.input_report) {
+				/* Resuming due to active touch*/
+				if (md->touch_state == WAKING_BY_ACTIVE_TOUCH) {
+					if (cd->drm_panel_state == DRM_PANEL_OFF) {
+						pt_debug(dev, DL_INFO,
+							 "%s: start to queue touch events\n",
+							 __func__);
+						md->touch_state = QUEUEING_TOUCH_EVENTS;
+						queue_input_event(EV_TIMESTAMP, 0, 0,
+								  cd->timestamp);
+					}
+					input_report_key(md->input, KEY_WAKEUP, 1);
+					input_sync(md->input);
+					input_report_key(md->input, KEY_WAKEUP, 0);
+					input_sync(md->input);
+				}
 				md->mt_function.input_report(md->input, sig,
 						t, tch->abs[PT_TCH_O]);
+			}
 			__set_bit(t, ids);
 		}
 
@@ -370,6 +454,9 @@
 		input_sync(md->input);
 		input_report_key(md->input, KEY_SLEEP, 0);
 		input_sync(md->input);
+		pt_mcu_send_key(KEY_SLEEP);
+		pt_mt_lift_all(md);
+		return 0;
 	}
 
 	if (num_cur_tch == 0 && md->num_prv_rec == 0)
@@ -378,6 +465,7 @@
 	/* extract xy_data for all currently reported touches */
 	pt_debug(dev, DL_DEBUG, "%s: extract data num_cur_tch=%d\n",
 		__func__, num_cur_tch);
+
 	if (num_cur_tch)
 		pt_get_mt_touches(md, &tch, num_cur_tch);
 	else
@@ -389,6 +477,34 @@
 	return rc;
 }
 
+static void pt_gesture_event_handle_orientation(struct pt_mt_data *md, uint32_t *input_x,
+						uint32_t *input_y)
+{
+	struct pt_sysinfo *si = md->si;
+	bool flipped;
+
+	if (md->pdata->flags & PT_MT_FLAG_FLIP) {
+		swap(*input_x, *input_y);
+		flipped = true;
+	} else {
+		flipped = false;
+	}
+
+	if (md->pdata->flags & PT_MT_FLAG_INV_X) {
+		if (flipped)
+			*input_x = si->sensing_conf_data.res_y - *input_x - 1;
+		else
+			*input_x = si->sensing_conf_data.res_x - *input_x - 1;
+	}
+
+	if (md->pdata->flags & PT_MT_FLAG_INV_Y) {
+		if (flipped)
+			*input_y = si->sensing_conf_data.res_x - *input_y - 1;
+		else
+			*input_y = si->sensing_conf_data.res_y - *input_y - 1;
+	}
+}
+
 /*******************************************************************************
  * FUNCTION: pt_mt_send_dummy_event
  *
@@ -423,29 +539,49 @@
 	u8 key_value = 0;
 
 	switch (cd->gesture_id) {
-	case GESTURE_DOUBLE_TAP:
-		key_value = KEY_F1;
-		break;
-	case GESTURE_TWO_FINGERS_SLIDE:
-		key_value = KEY_F2;
-		break;
-	case GESTURE_TOUCH_DETECTED:
-		key_value = KEY_WAKEUP;
-		break;
-	case GESTURE_PUSH_BUTTON:
-		key_value = KEY_F4;
-		break;
+	case GESTURE_SINGLE_TAP: {
+		uint32_t input_x =
+			(uint32_t)(cd->gesture_data[1] << 8) + (uint32_t)(cd->gesture_data[0]);
+		uint32_t input_y =
+			(uint32_t)(cd->gesture_data[3] << 8) + (uint32_t)(cd->gesture_data[2]);
+
+		pt_gesture_event_handle_orientation(md, &input_x, &input_y);
+		pt_debug(md->dev, DL_INFO,
+			 "%s:Gesture : Tap to Wake, coordinates (%d,%d) instead of keycode.\n",
+			 __func__, input_x, input_y);
+		/* Send finger down */
+		input_mt_slot(md->input, 0);
+		input_mt_report_slot_state(md->input, MT_TOOL_FINGER, true);
+		input_report_abs(md->input, ABS_MT_POSITION_X, input_x);
+		input_report_abs(md->input, ABS_MT_POSITION_Y, input_y);
+		/* Placeholder pressure value, without this the
+		 * touch is interpreted as a hover.
+		 */
+		input_report_abs(md->input, ABS_MT_PRESSURE, 0x300);
+		input_mt_sync_frame(md->input);
+		input_sync(md->input);
+
+		/* Send finger up */
+		input_mt_slot(md->input, 0);
+		input_report_abs(md->input, ABS_MT_TOUCH_MAJOR, 0);
+		input_mt_report_slot_state(md->input, MT_TOOL_FINGER, false);
+		input_mt_sync_frame(md->input);
+		input_sync(md->input);
+	} break;
 	case GESTURE_SINGLE_SLIDE_DE_TX:
-		key_value = KEY_F5;
+		key_value = KEY_UP;
 		break;
 	case GESTURE_SINGLE_SLIDE_IN_TX:
-		key_value = KEY_F6;
+		key_value = KEY_DOWN;
 		break;
 	case GESTURE_SINGLE_SLIDE_DE_RX:
-		key_value = KEY_F7;
+		key_value = KEY_RIGHT;
 		break;
 	case GESTURE_SINGLE_SLIDE_IN_RX:
-		key_value = KEY_F8;
+		key_value = KEY_LEFT;
+		break;
+	case GESTURE_PALM:
+		pt_mcu_send_key(KEY_SLEEP);
 		break;
 	default:
 		break;
@@ -453,7 +589,7 @@
 
 	if (key_value > 0) {
 		input_report_key(md->input, key_value, 1);
-		mdelay(10);
+		input_sync(md->input);
 		input_report_key(md->input, key_value, 0);
 		input_sync(md->input);
 	}
@@ -462,8 +598,8 @@
 	 * Caution - this debug print is needed by the TTDL automated
 	 *           regression test suite
 	 */
-	pt_debug(md->dev, DL_INFO, "%s: report key: %d\n",
-		__func__, key_value);
+	pt_debug(md->dev, DL_INFO, "%s: report key: %d. gesture_id: %d\n", __func__, key_value,
+		 cd->gesture_id);
 #endif
 }
 
@@ -491,7 +627,11 @@
 
 	/* core handles handshake */
 	mutex_lock(&md->mt_lock);
-	input_set_timestamp(md->input, cd->timestamp);
+	if (md->touch_state == QUEUEING_TOUCH_EVENTS) {
+		queue_input_event(EV_TIMESTAMP, 0, 0, cd->timestamp);
+	} else {
+		input_set_timestamp(md->input, cd->timestamp);
+	}
 	rc = pt_xy_worker(md);
 	mutex_unlock(&md->mt_lock);
 	if (rc < 0)
@@ -573,7 +713,9 @@
 	md->is_suspended = true;
 	mutex_unlock(&md->mt_lock);
 
-	pm_runtime_put(dev);
+	if (!(cd->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME)) {
+		pm_runtime_put(dev);
+	}
 
 	return 0;
 }
@@ -596,7 +738,9 @@
 	struct pt_core_data *cd = dev_get_drvdata(dev);
 	struct pt_mt_data *md = &cd->md;
 
-	pm_runtime_get(dev);
+	if (!(cd->cpdata->flags & PT_CORE_FLAG_SKIP_RUNTIME)) {
+		pm_runtime_get(dev);
+	}
 
 	mutex_lock(&md->mt_lock);
 	md->is_suspended = false;
@@ -789,14 +933,10 @@
 		md->input_device_registered = true;
 
 #ifdef EASYWAKE_TSG6
-	input_set_capability(md->input, EV_KEY, KEY_F1);
-	input_set_capability(md->input, EV_KEY, KEY_F2);
-	input_set_capability(md->input, EV_KEY, KEY_F3);
-	input_set_capability(md->input, EV_KEY, KEY_F4);
-	input_set_capability(md->input, EV_KEY, KEY_F5);
-	input_set_capability(md->input, EV_KEY, KEY_F6);
-	input_set_capability(md->input, EV_KEY, KEY_F7);
-	input_set_capability(md->input, EV_KEY, KEY_F8);
+	input_set_capability(md->input, EV_KEY, KEY_UP);
+	input_set_capability(md->input, EV_KEY, KEY_LEFT);
+	input_set_capability(md->input, EV_KEY, KEY_RIGHT);
+	input_set_capability(md->input, EV_KEY, KEY_DOWN);
 	input_set_capability(md->input, EV_KEY, KEY_WAKEUP);
 	input_set_capability(md->input, EV_KEY, KEY_SLEEP);
 #endif
diff --git a/tma525c/pt_mtb.c b/tma525c/pt_mtb.c
index 124e723..d29ae93 100644
--- a/tma525c/pt_mtb.c
+++ b/tma525c/pt_mtb.c
@@ -32,6 +32,8 @@
 #include <linux/input/mt.h>
 #include <linux/version.h>
 
+extern struct pt_input_event touch_event_list_head;
+extern void queue_input_event(uint16_t type, uint16_t code, int32_t value, ktime_t timestamp);
 /*******************************************************************************
  * FUNCTION: pt_final_sync
  *
@@ -47,15 +49,25 @@
 		int mt_sync_count, unsigned long *ids)
 {
 	int t;
+	struct pt_core_data *core_data = pt_get_core_data(PT_DEFAULT_CORE_ID);
+	struct pt_mt_data *md = &core_data->md;
 
 	for (t = 0; t < max_slots; t++) {
 		if (test_bit(t, ids))
 			continue;
-		input_mt_slot(input, t);
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS) {
+			queue_input_event(EV_ABS, ABS_MT_SLOT, t, 0);
+			queue_input_event(EV_SLOT_STATE, MT_TOOL_FINGER, false, 0);
+		} else {
+			input_mt_slot(input, t);
+			input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+		}
 	}
-
-	input_sync(input);
+	if (md->touch_state == QUEUEING_TOUCH_EVENTS) {
+		queue_input_event(EV_SYN, SYN_REPORT, 0, 0);
+	} else {
+		input_sync(input);
+	}
 }
 
 /*******************************************************************************
@@ -73,12 +85,25 @@
 static void pt_input_report(struct input_dev *input, int sig,
 		int t, int type)
 {
-	input_mt_slot(input, t);
+	struct pt_core_data *core_data = pt_get_core_data(PT_DEFAULT_CORE_ID);
+	struct pt_mt_data *md = &core_data->md;
 
-	if (type == PT_OBJ_STANDARD_FINGER || type == PT_OBJ_GLOVE)
-		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
-	else if (type == PT_OBJ_STYLUS)
-		input_mt_report_slot_state(input, MT_TOOL_PEN, true);
+	if (md->touch_state == QUEUEING_TOUCH_EVENTS)
+		queue_input_event(EV_ABS, ABS_MT_SLOT, t, 0);
+	else
+		input_mt_slot(input, t);
+
+	if (type == PT_OBJ_STANDARD_FINGER || type == PT_OBJ_GLOVE) {
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS)
+			queue_input_event(EV_SLOT_STATE, MT_TOOL_FINGER, true, 0);
+		else
+			input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+	} else if (type == PT_OBJ_STYLUS) {
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS)
+			queue_input_event(EV_SLOT_STATE, MT_TOOL_PEN, true, 0);
+		else
+			input_mt_report_slot_state(input, MT_TOOL_PEN, true);
+	}
 }
 
 /*******************************************************************************
@@ -100,9 +125,13 @@
 		return;
 
 	for (t = 0; t < max_slots; t++) {
-		input_mt_slot(md->input, t);
-		input_mt_report_slot_state(md->input,
-			MT_TOOL_FINGER, false);
+		if (md->touch_state == QUEUEING_TOUCH_EVENTS) {
+			queue_input_event(EV_ABS, ABS_MT_SLOT, t, 0);
+			queue_input_event(EV_SLOT_STATE, MT_TOOL_FINGER, false, 0);
+		} else {
+			input_mt_slot(md->input, t);
+			input_mt_report_slot_state(md->input, MT_TOOL_FINGER, false);
+		}
 	}
 }
 
diff --git a/tma525c/pt_regs.h b/tma525c/pt_regs.h
index 3694023..d0b54a1 100644
--- a/tma525c/pt_regs.h
+++ b/tma525c/pt_regs.h
@@ -497,14 +497,12 @@
 #define PANEL_ID_NOT_ENABLED	0xFF
 
 #ifdef EASYWAKE_TSG6
-#define GESTURE_DOUBLE_TAP         (1)
-#define GESTURE_TWO_FINGERS_SLIDE  (2)
-#define GESTURE_TOUCH_DETECTED     (3)
-#define GESTURE_PUSH_BUTTON        (4)
-#define GESTURE_SINGLE_SLIDE_DE_TX (5)
-#define GESTURE_SINGLE_SLIDE_IN_TX (6)
-#define GESTURE_SINGLE_SLIDE_DE_RX (7)
-#define GESTURE_SINGLE_SLIDE_IN_RX (8)
+#define GESTURE_SINGLE_TAP	   0x02
+#define GESTURE_SINGLE_SLIDE_DE_TX 0x04
+#define GESTURE_SINGLE_SLIDE_IN_TX 0x08
+#define GESTURE_SINGLE_SLIDE_DE_RX 0x10
+#define GESTURE_SINGLE_SLIDE_IN_RX 0x20
+#define GESTURE_PALM		   0x40
 #endif
 
 /* FW RAM parameters */
@@ -1387,6 +1385,7 @@
 
 enum pt_drm_panel_state {
 	DRM_PANEL_ON,
+	DRM_PANEL_LP,
 	DRM_PANEL_OFF,
 };
 
@@ -1460,6 +1459,12 @@
 	int (*input_register_device)(struct input_dev *input, int max_slots);
 };
 
+enum touch_state {
+	NORMAL,
+	WAKING_BY_ACTIVE_TOUCH,
+	QUEUEING_TOUCH_EVENTS,
+};
+
 struct pt_mt_data {
 	struct device *dev;
 	struct pt_mt_platform_data *pdata;
@@ -1476,6 +1481,7 @@
 	int or_max;
 	int t_min;
 	int t_max;
+	uint8_t touch_state;
 };
 
 struct pt_pen_data {
@@ -1917,6 +1923,20 @@
 	int32_t gradient_val;
 };
 
+struct pt_input_event {
+	uint16_t type;
+	uint16_t code;
+	int32_t value;
+	ktime_t timestamp;
+	struct list_head list;
+};
+
+enum INPUT_EVENT_TYPE {
+	EV_TIMESTAMP = 0x18,
+	EV_SLOT_STATE = 0x19,
+	EV_SYNC_FRAME = 0x1a,
+};
+
 #ifdef TTHE_TUNER_SUPPORT
 #define PT_CMD_RET_PANEL_IN_DATA_OFFSET	0
 #define PT_CMD_RET_PANEL_ELMNT_SZ_MASK	0x07