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