diff options
author | Will McVicker <willmcvicker@google.com> | 2023-11-03 16:24:57 -0700 |
---|---|---|
committer | Will McVicker <willmcvicker@google.com> | 2023-11-03 16:24:57 -0700 |
commit | 0c81a452691e3c1004e638cb09bc3a0282213b21 (patch) | |
tree | 90df6daf050c2d85bfc87dce1e240ec5accac7e1 | |
parent | 07200384a6b3202931b6d1151c6a226124cf8a79 (diff) | |
parent | cb1ce1fb12115861672af8282416ed591b14b038 (diff) | |
download | common-0c81a452691e3c1004e638cb09bc3a0282213b21.tar.gz |
Merge aosp/android-gs-raviole-5.10-android14 into android-gs-raviole-mainline
* aosp/android-gs-raviole-5.10-android14: (115 commits)
gti: request GTI_PM_WAKELOCK_TYPE_IRQ when TBN enabled
gti: add IRQ wakelock
gti: Acquire the wakelock before applying FW settings
gti: Adjust the panel_bridge_enable logs level to debug
touch/common: add TBN mock mode
gti: support predefined dev id to create device
goog_touch_interface: Add power supply status
gti: report driver status every frame
gti: update display status instead of pm_state for screen_state
touch_offload: fix delete cdev twice
touch/gti: Add coordinate filter
input: touch_offload: interface updates
gti: add firmware setting logs
gti: update the screen state when the driver suspend.
gti: remove ignore_screenoff_heatmap
gti: remove touch rawdata sysfs command.
gti: Correct the probe sequence to initialize the input.
gti: Correct the probe sequence to initialize the input.
gti: Correct the probe sequence to initialize the input.
gti: update driver status for touch_offload
gti: support fw water mode status change
gti: fix heatmap protection
kleaf: add AOC dependency
touch/common: refine debugging message
touch/common: fix crash when tbn is disabled
Revert^2 "touch/common: suppport aoc cannel mode for tbn"
Revert "touch/common: suppport aoc cannel mode for tbn"
gti: add atrace for offload input report.
gti: Support procfs to get heatmap.
gti: change the default mode for dumpstate logs.
gti: change the default mode for dumpstate logs.
gti: Check VRR is enabled or not before setting touch report rate
kleaf: add AOC dependencies
kleaf: switch to generic label_flags
touch/common: return EPROBE_DEFER when the GPIO is invalid.
touch/common: return EPROBE_DEFER when the GPIO is invalid.
gti: Support procfs to get heatmap.
touch/common: suppport aoc cannel mode for tbn
gti: Add logs for unexpected tool_type by vendor driver
gti: Add logs for unexpected tool_type by vendor driver
touch/gti: Add touch index in GTI log
touch/gti: Add touch index in GTI log
touch: gti: Added wakelock_nosync support
touch: gti: Added wakelock_nosync support
touch: gti: Fix spi write error.
touch: gti: Fix spi write error.
gti: replace manual_sensing_lock by input_process_lock
touch/gti: Add a new line after showing SS data
gti: replace manual_sensing_lock by input_process_lock
touch/gti: Only handle display state if changed
touch/gti: Add a new line after showing SS data
touch/gti: Only handle display state if changed
gti: replace manual_sensing_lock by input_process_lock
touch_offload: fix mixed use register_chrdev and cdev_add
touch/gti: fully remove sysfs when removing gti
touch/gti: release all fingers when the device suspends
touch/gti: release all fingers when the device suspends
touch/gti: release all fingers when the device suspends
touch/gti: support variable report rate
touch: Add fw_grip and fw_palm sysfs node
touch: Add fw_grip and fw_palm sysfs node
touch/TBN: Double check the value of aoc2ap_gpio when timeout
touch/TBN: Double check the value of aoc2ap_gpio when timeout
touch/gti: Correct the typo of firmware status enumeration
touch/gti: Transport touch_offload driver/stylus context
touch/gti: adjust the output format width by size.
heatmap: add vb2_queue_release in module remove
touch/gti: Add frame index into atrace.
touch/gti: Refine the GTI logs for touch offload.
touch/gti: Support custom offload device name from DT.
touch/gti: fix data racing
touch/gti: Support pm qos.
touch/gti: Support pm qos.
touch/gti: Support pm qos.
touch: common: fix double includes of heatmap.h
touch/gti: support the capability check for SPI dma enabled.
touch/gti: support the capability check for SPI dma enabled.
touch: common: fix double includes of heatmap.h
touch/gti: support the capability check for SPI dma enabled.
touch/gti: process input after vendor irq complete.
touch/gti: process input after vendor irq complete.
touch/gti: initialize input abs to support shape algo reporting.
touch/gti: initialize input abs to support shape algo reporting.
touch/gti: initialize input to support orientation reporting.
touch/gti: initialize input to support orientation reporting.
touch/gti: support interrupt debug logs.
touch/gti: support interrupt debug logs.
touch/gti: fix the race condition between drm and pm
touch/gti: fix the race condition between drm and pm
touch/gti: refine the naming of features enabled.
touch/gti: refine the force active.
touch/gti: fix build error for 5.15 kernel
touch/gti: refine the naming of features enabled.
touch/gti: refine the force active.
touch/gti: fix offload caps for orientation
touch/gti: Support mutual and self sensing data for sysfs
touch/gti: add goog_notify_fw_status_changed
touch/gti: enable heatamp when updating fw settings.
touch/gti: support touch cancel reporting by MT_TOOL_PALM.
touch/gti: add the ability to report orientation.
...
Change-Id: I0cbc6709e0dffdbed0cefc573bd9aa1490042001
Signed-off-by: Will McVicker <willmcvicker@google.com>
-rw-r--r-- | BUILD.bazel | 6 | ||||
-rw-r--r-- | Kbuild | 11 | ||||
-rw-r--r-- | Kconfig | 8 | ||||
-rw-r--r-- | Makefile | 27 | ||||
-rw-r--r-- | goog_touch_interface.c | 2414 | ||||
-rw-r--r-- | goog_touch_interface.h | 285 | ||||
-rw-r--r-- | goog_touch_interface_nop.h | 2 | ||||
-rw-r--r-- | heatmap.c | 8 | ||||
-rw-r--r-- | heatmap.h | 7 | ||||
-rw-r--r-- | include/uapi/input/touch_offload.h | 8 | ||||
-rw-r--r-- | touch_bus_negotiator.c | 284 | ||||
-rw-r--r-- | touch_bus_negotiator.h | 39 | ||||
-rw-r--r-- | touch_offload.c | 67 | ||||
-rw-r--r-- | touch_offload.h | 6 |
14 files changed, 2350 insertions, 822 deletions
diff --git a/BUILD.bazel b/BUILD.bazel index 447bc3d..54b14f7 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,11 +13,12 @@ filegroup( ) filegroup( - name = "common.kconfig", + name = "touch.common.kconfig", srcs = glob([ "Kconfig", ]), visibility = [ + "//private/devices/google:__subpackages__", "//private/google-modules/soc/gs:__pkg__", ], ) @@ -29,6 +30,7 @@ kernel_module( "**/*.h", "Kbuild", ]) + [ + "//private/google-modules/aoc:headers", "//private/google-modules/display:headers", "//private/google-modules/display/include:headers", "//private/google-modules/soc/gs:gs_soc_headers", @@ -41,10 +43,12 @@ kernel_module( ], kernel_build = "//private/google-modules/soc/gs:gs_kernel_build", visibility = [ + "//private/devices/google:__subpackages__", "//private/google-modules/soc/gs:__pkg__", "//private/google-modules/touch:__subpackages__", ], deps = [ + "//private/google-modules/aoc", "//private/google-modules/soc/gs:gs_soc_module", ], ) @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -ccflags-y += -I$(srctree)/$(src)/include -ccflags-y += -I$(srctree)/../private/google-modules/display -ccflags-y += -I$(srctree)/../private/google-modules/display/include/uapi - -obj-$(CONFIG_TOUCHSCREEN_TBN) += touch_bus_negotiator.o -obj-$(CONFIG_TOUCHSCREEN_HEATMAP) += heatmap.o -obj-$(CONFIG_TOUCHSCREEN_OFFLOAD) += touch_offload.o -obj-$(CONFIG_GOOG_TOUCH_INTERFACE) += goog_touch_interface.o - @@ -20,6 +20,14 @@ config TOUCHSCREEN_TBN To compile this driver as a module, choose M here: the module will be called touch_bus_negotiator. +config TOUCHSCREEN_TBN_AOC_CHANNEL_MODE + bool "AOC channel mode for TBN" + depends on TOUCHSCREEN_TBN + help + Say Y here if you want to enable AOC channel mode for TBN. + + If unsure, say N. + config TOUCHSCREEN_OFFLOAD tristate "Touchscreen algorithm offload" depends on (TOUCHSCREEN_FTS || TOUCHSCREEN_SEC_TS) @@ -1,14 +1,31 @@ -# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_TOUCHSCREEN_TBN) += touch_bus_negotiator.o +obj-$(CONFIG_TOUCHSCREEN_HEATMAP) += heatmap.o +obj-$(CONFIG_TOUCHSCREEN_OFFLOAD) += touch_offload.o +obj-$(CONFIG_GOOG_TOUCH_INTERFACE) += goog_touch_interface.o KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build M ?= $(shell pwd) +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_TBN=m +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_HEATMAP=m +KBUILD_OPTIONS += CONFIG_TOUCHSCREEN_OFFLOAD=m +KBUILD_OPTIONS += CONFIG_GOOG_TOUCH_INTERFACE=m EXTRA_CFLAGS += -DDYNAMIC_DEBUG_MODULE +EXTRA_CFLAGS += -I$(KERNEL_SRC)/../google-modules/touch/common/include +EXTRA_CFLAGS += -I$(KERNEL_SRC)/../google-modules/display -include $(KERNEL_SRC)/../private/google-modules/soc/gs/Makefile.include +modules clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) \ + $(KBUILD_OPTIONS) \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + $(@) -modules modules_install headers_install clean: +modules_install: $(MAKE) -C $(KERNEL_SRC) M=$(M) \ - EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" $(@) + $(KBUILD_OPTIONS) \ + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ + $(@) -modules_install: headers_install +headers_install: + $(MAKE) -C $(KERNEL_SRC) M=$(M) \ + $(@) diff --git a/goog_touch_interface.c b/goog_touch_interface.c index 7766d95..9741aeb 100644 --- a/goog_touch_interface.c +++ b/goog_touch_interface.c @@ -8,10 +8,14 @@ #include <linux/module.h> #include <linux/input/mt.h> #include <linux/of.h> +#include <linux/power_supply.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <samsung/exynos_drm_connector.h> #include "goog_touch_interface.h" #include "touch_bus_negotiator.h" +#include "../../../gs-google/drivers/soc/google/vh/kernel/systrace.h" static struct class *gti_class; static u8 gti_dev_num; @@ -20,6 +24,301 @@ static u8 gti_dev_num; * GTI/common: forward declarations, structures and functions. */ static void goog_offload_set_running(struct goog_touch_interface *gti, bool running); +static void goog_lookup_touch_report_rate(struct goog_touch_interface *gti); +static int goog_precheck_heatmap(struct goog_touch_interface *gti); +static void goog_set_display_state(struct goog_touch_interface *gti, + enum gti_display_state_setting display_state); + +/*----------------------------------------------------------------------------- + * GTI/proc: forward declarations, structures and functions. + */ +static int goog_proc_ms_base_show(struct seq_file *m, void *v); +static int goog_proc_ms_diff_show(struct seq_file *m, void *v); +static int goog_proc_ms_raw_show(struct seq_file *m, void *v); +static int goog_proc_ss_base_show(struct seq_file *m, void *v); +static int goog_proc_ss_diff_show(struct seq_file *m, void *v); +static int goog_proc_ss_raw_show(struct seq_file *m, void *v); +static struct proc_dir_entry *gti_proc_dir_root; +static char *gti_proc_name[GTI_PROC_NUM] = { + [GTI_PROC_MS_BASE] = "ms_base", + [GTI_PROC_MS_DIFF] = "ms_diff", + [GTI_PROC_MS_RAW] = "ms_raw", + [GTI_PROC_SS_BASE] = "ss_base", + [GTI_PROC_SS_DIFF] = "ss_diff", + [GTI_PROC_SS_RAW] = "ss_raw", +}; +static int (*gti_proc_show[GTI_PROC_NUM]) (struct seq_file *, void *) = { + [GTI_PROC_MS_BASE] = goog_proc_ms_base_show, + [GTI_PROC_MS_DIFF] = goog_proc_ms_diff_show, + [GTI_PROC_MS_RAW] = goog_proc_ms_raw_show, + [GTI_PROC_SS_BASE] = goog_proc_ss_base_show, + [GTI_PROC_SS_DIFF] = goog_proc_ss_diff_show, + [GTI_PROC_SS_RAW] = goog_proc_ss_raw_show, +}; +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ms_base); +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ms_diff); +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ms_raw); +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ss_base); +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ss_diff); +DEFINE_PROC_SHOW_ATTRIBUTE(goog_proc_ss_raw); + +static void goog_proc_heatmap_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; + u16 tx = gti->offload.caps.tx_size; + u16 rx = gti->offload.caps.rx_size; + int x, y; + + if (cmd->size == 0 || cmd->buffer == NULL) { + seq_puts(m, "result: N/A!\n"); + GOOG_WARN(gti, "result: N/A!\n"); + return; + } + + switch (cmd->type) { + case GTI_SENSOR_DATA_TYPE_MS_BASELINE: + case GTI_SENSOR_DATA_TYPE_MS_DIFF: + case GTI_SENSOR_DATA_TYPE_MS_RAW: + if (cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { + seq_puts(m, "result:\n"); + for (y = 0; y < rx; y++) { + for (x = 0; x < tx; x++) + seq_printf(m, "%5d,", ((s16 *)cmd->buffer)[y * tx + x]); + seq_puts(m, "\n"); + } + } else { + seq_printf(m, "error: invalid buffer %p or size %d!\n", + cmd->buffer, cmd->size); + GOOG_WARN(gti, "error: invalid buffer %p or size %d!\n", + cmd->buffer, cmd->size); + } + break; + + case GTI_SENSOR_DATA_TYPE_SS_BASELINE: + case GTI_SENSOR_DATA_TYPE_SS_DIFF: + case GTI_SENSOR_DATA_TYPE_SS_RAW: + if (cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { + seq_puts(m, "result:\n"); + seq_puts(m, "TX:"); + for (x = 0; x < tx; x++) + seq_printf(m, "%5d,", ((s16 *)cmd->buffer)[x]); + seq_puts(m, "\nRX:"); + for (y = 0; y < rx; y++) + seq_printf(m, "%5d,", ((s16 *)cmd->buffer)[tx + y]); + seq_puts(m, "\n"); + } else { + seq_printf(m, "error: invalid buffer %p or size %d!\n", + cmd->buffer, cmd->size); + GOOG_WARN(gti, "error: invalid buffer %p or size %d!\n", + cmd->buffer, cmd->size); + } + break; + + default: + seq_printf(m, "error: invalid type %#x!\n", cmd->type); + GOOG_ERR(gti, "error: invalid type %#x!\n", cmd->type); + break; + } +} + +static int goog_proc_heatmap_process(struct seq_file *m, void *v, enum gti_sensor_data_type type) +{ + struct goog_touch_interface *gti = m->private; + struct gti_sensor_data_cmd *cmd = >i->cmd.manual_sensor_data_cmd; + int ret = 0; + + ret = goog_precheck_heatmap(gti); + if (ret) { + seq_puts(m, "N/A!\n"); + goto heatmap_process_err; + } + + switch (type) { + case GTI_SENSOR_DATA_TYPE_MS_BASELINE: + case GTI_SENSOR_DATA_TYPE_MS_DIFF: + case GTI_SENSOR_DATA_TYPE_MS_RAW: + case GTI_SENSOR_DATA_TYPE_SS_BASELINE: + case GTI_SENSOR_DATA_TYPE_SS_DIFF: + case GTI_SENSOR_DATA_TYPE_SS_RAW: + cmd->type = type; + break; + + default: + seq_printf(m, "error: invalid type %#x!\n", type); + GOOG_ERR(gti, "error: invalid type %#x!\n", type); + ret = -EINVAL; + break; + } + + if (ret) + goto heatmap_process_err; + + cmd->buffer = NULL; + cmd->size = 0; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA_MANUAL); + if (ret) { + seq_printf(m, "error: %d!\n", ret); + GOOG_ERR(gti, "error: %d!\n", ret); + } else { + GOOG_INFO(gti, "type %#x.\n", type); + } + +heatmap_process_err: + if (ret) { + cmd->buffer = NULL; + cmd->size = 0; + } + return ret; +} + +static int goog_proc_ms_base_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_MS_BASELINE); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static int goog_proc_ms_diff_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_MS_DIFF); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static int goog_proc_ms_raw_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_MS_RAW); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static int goog_proc_ss_base_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_SS_BASELINE); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static int goog_proc_ss_diff_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_SS_DIFF); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static int goog_proc_ss_raw_show(struct seq_file *m, void *v) +{ + struct goog_touch_interface *gti = m->private; + int ret; + + ret = mutex_lock_interruptible(>i->input_process_lock); + if (ret) { + seq_puts(m, "error: has been interrupted!\n"); + GOOG_WARN(gti, "error: has been interrupted!\n"); + return ret; + } + + ret = goog_proc_heatmap_process(m, v, GTI_SENSOR_DATA_TYPE_SS_RAW); + if (!ret) + goog_proc_heatmap_show(m, v); + mutex_unlock(>i->input_process_lock); + + return ret; +} + +static void goog_init_proc(struct goog_touch_interface *gti) +{ + int type; + + if (!gti_proc_dir_root) { + gti_proc_dir_root = proc_mkdir(GTI_NAME, NULL); + if (!gti_proc_dir_root) { + pr_err("%s: proc_mkdir failed for %s!\n", __func__, GTI_NAME); + return; + } + } + + gti->proc_dir = proc_mkdir_data(dev_name(gti->dev), 0555, gti_proc_dir_root, gti); + if (!gti->proc_dir) { + GOOG_ERR(gti, "proc_mkdir_data failed!\n"); + return; + } + + for (type = GTI_PROC_MS_BASE; type < GTI_PROC_NUM; type++) { + char *name = gti_proc_name[type]; + + if (gti_proc_show[type]) + gti->proc_heatmap[type] = proc_create_single_data( + name, 0555, gti->proc_dir, gti_proc_show[type], gti); + if (!gti->proc_heatmap[type]) + GOOG_ERR(gti, "proc_create_single_data failed for %s!\n", name); + } +} /*----------------------------------------------------------------------------- * GTI/sysfs: forward declarations, structures and functions. @@ -28,12 +327,20 @@ static ssize_t force_active_show( struct device *dev, struct device_attribute *attr, char *buf); static ssize_t force_active_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); -static ssize_t fw_ver_show(struct device *dev, +static ssize_t fw_coord_filter_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t fw_coord_filter_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); +static ssize_t fw_grip_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t grip_enabled_show(struct device *dev, +static ssize_t fw_grip_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); +static ssize_t fw_palm_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t grip_enabled_store(struct device *dev, +static ssize_t fw_palm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t fw_ver_show(struct device *dev, + struct device_attribute *attr, char *buf); static ssize_t irq_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t irq_enabled_store(struct device *dev, @@ -42,20 +349,10 @@ static ssize_t mf_mode_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t mf_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); -static ssize_t ms_base_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ms_diff_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ms_raw_show(struct device *dev, - struct device_attribute *attr, char *buf); static ssize_t offload_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t offload_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); -static ssize_t palm_enabled_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size); -static ssize_t palm_enabled_show(struct device *dev, - struct device_attribute *attr, char *buf); static ssize_t ping_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t reset_show(struct device *dev, @@ -72,12 +369,6 @@ static ssize_t screen_protector_mode_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t self_test_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t ss_base_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ss_diff_show(struct device *dev, - struct device_attribute *attr, char *buf); -static ssize_t ss_raw_show(struct device *dev, - struct device_attribute *attr, char *buf); static ssize_t sensing_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sensing_enabled_store(struct device *dev, @@ -86,49 +377,45 @@ static ssize_t v4l2_enabled_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t v4l2_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t vrr_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t vrr_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); static DEVICE_ATTR_RW(force_active); +static DEVICE_ATTR_RW(fw_coord_filter); +static DEVICE_ATTR_RW(fw_grip); +static DEVICE_ATTR_RW(fw_palm); static DEVICE_ATTR_RO(fw_ver); -static DEVICE_ATTR_RW(grip_enabled); static DEVICE_ATTR_RW(irq_enabled); static DEVICE_ATTR_RW(mf_mode); -static DEVICE_ATTR_RO(ms_base); -static DEVICE_ATTR_RO(ms_diff); -static DEVICE_ATTR_RO(ms_raw); static DEVICE_ATTR_RW(offload_enabled); -static DEVICE_ATTR_RW(palm_enabled); static DEVICE_ATTR_RO(ping); static DEVICE_ATTR_RW(reset); static DEVICE_ATTR_RW(scan_mode); static DEVICE_ATTR_RW(screen_protector_mode_enabled); static DEVICE_ATTR_RO(self_test); -static DEVICE_ATTR_RO(ss_base); -static DEVICE_ATTR_RO(ss_diff); -static DEVICE_ATTR_RO(ss_raw); static DEVICE_ATTR_RW(sensing_enabled); static DEVICE_ATTR_RW(v4l2_enabled); +static DEVICE_ATTR_RW(vrr_enabled); static struct attribute *goog_attributes[] = { &dev_attr_force_active.attr, + &dev_attr_fw_coord_filter.attr, + &dev_attr_fw_grip.attr, + &dev_attr_fw_palm.attr, &dev_attr_fw_ver.attr, - &dev_attr_grip_enabled.attr, &dev_attr_irq_enabled.attr, &dev_attr_mf_mode.attr, - &dev_attr_ms_base.attr, - &dev_attr_ms_diff.attr, - &dev_attr_ms_raw.attr, &dev_attr_offload_enabled.attr, - &dev_attr_palm_enabled.attr, &dev_attr_ping.attr, &dev_attr_reset.attr, &dev_attr_scan_mode.attr, &dev_attr_screen_protector_mode_enabled.attr, &dev_attr_self_test.attr, - &dev_attr_ss_base.attr, - &dev_attr_ss_diff.attr, - &dev_attr_ss_raw.attr, &dev_attr_sensing_enabled.attr, &dev_attr_v4l2_enabled.attr, + &dev_attr_vrr_enabled.attr, NULL, }; @@ -140,15 +427,20 @@ static ssize_t force_active_show( struct device *dev, struct device_attribute *attr, char *buf) { struct goog_touch_interface *gti = dev_get_drvdata(dev); - int ret = 0; + ssize_t buf_idx = 0; bool locked = false; + if (gti->ignore_force_active) { + GOOG_WARN(gti, "operation not supported!\n"); + return -EOPNOTSUPP; + } + locked = goog_pm_wake_check_locked(gti, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE); - ret = snprintf(buf, PAGE_SIZE, "result: %s\n", + buf_idx += scnprintf(buf, PAGE_SIZE - buf_idx, "result: %s\n", locked ? "locked" : "unlocked"); - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); - return ret; + return buf_idx; } static ssize_t force_active_store(struct device *dev, @@ -159,383 +451,349 @@ static ssize_t force_active_store(struct device *dev, int ret = 0; if (buf == NULL || size < 0) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } if (kstrtou32(buf, 10, &locked)) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } if (locked > 1) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } - if (locked) - ret = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE, false); - else - ret = goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE); + if (locked) { + gti_debug_hc_dump(gti); + gti_debug_input_dump(gti); + if (gti->ignore_force_active) + GOOG_WARN(gti, "operation not supported!\n"); + else + ret = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE, false); + } else { + if (gti->ignore_force_active) + GOOG_WARN(gti, "operation not supported!\n"); + else + ret = goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE); + } if (ret < 0) { - GOOG_LOG("error: %d!\n", ret); + GOOG_INFO(gti, "error: %d!\n", ret); return ret; } return size; } -static ssize_t fw_ver_show(struct device *dev, +static ssize_t fw_coord_filter_show(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + int ret = 0; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); + struct gti_coord_filter_cmd *cmd = >i->cmd.coord_filter_cmd; - memset(gti->cmd.fw_version_cmd.buffer, 0, sizeof(gti->cmd.fw_version_cmd.buffer)); - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_FW_VERSION); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + if (!gti->coord_filter_enabled) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %s\n", gti->cmd.fw_version_cmd.buffer); + GOOG_INFO(gti, "%s", buf); + return buf_idx; } - GOOG_LOG("%s", buf); - - return buf_idx; -} - -static ssize_t grip_enabled_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int ret = 0; - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_grip_cmd *cmd = >i->cmd.grip_cmd; - cmd->setting = GTI_GRIP_DISABLE; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_GRIP_MODE); + cmd->setting = GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_COORD_FILTER_ENABLED); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %u\n", cmd->setting); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", cmd->setting | (gti->ignore_coord_filter_update << 1)); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } -static ssize_t grip_enabled_store(struct device *dev, +static ssize_t fw_coord_filter_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int ret = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_grip_cmd *cmd = >i->cmd.grip_cmd; - bool enabled = false; + int fw_coord_filter; - if (kstrtobool(buf, &enabled)) { - GOOG_LOG("error: invalid input!\n"); - return size; + if (kstrtou32(buf, 10, &fw_coord_filter)) { + GOOG_INFO(gti, "error: invalid input!\n"); + return -EINVAL; } - cmd->setting = enabled ? GTI_GRIP_ENABLE : GTI_GRIP_DISABLE; - ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_GRIP_MODE); + if (!gti->coord_filter_enabled) { + GOOG_INFO(gti, "error: not supported!\n"); + return -EOPNOTSUPP; + } + + gti->fw_coord_filter_enabled = fw_coord_filter & 0x01; + gti->ignore_coord_filter_update = (fw_coord_filter >> 1) & 0x01; + gti->cmd.coord_filter_cmd.setting = gti->fw_coord_filter_enabled ? + GTI_COORD_FILTER_ENABLE : GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_COORD_FILTER_ENABLED); if (ret == -EOPNOTSUPP) - GOOG_LOG("error: not supported!\n"); + GOOG_INFO(gti, "error: not supported!\n"); else if (ret) - GOOG_LOG("error: %d!\n", ret); + GOOG_INFO(gti, "error: %d!\n", ret); else - GOOG_LOG("grip_enabled= %u\n", cmd->setting); + GOOG_INFO(gti, "fw_coord_filter= %u\n", fw_coord_filter); return size; } -static ssize_t irq_enabled_show(struct device *dev, +static ssize_t fw_grip_show(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + int ret = 0; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); + struct gti_grip_cmd *cmd = >i->cmd.grip_cmd; - gti->cmd.irq_cmd.setting = GTI_IRQ_MODE_NA; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_IRQ_MODE); + cmd->setting = GTI_GRIP_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_GRIP_MODE); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %u\n", gti->cmd.irq_cmd.setting); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", cmd->setting | (gti->ignore_grip_update << 1)); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } -static ssize_t irq_enabled_store(struct device *dev, +static ssize_t fw_grip_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int ret; - bool enabled; + int ret = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); + int fw_grip_mode = 0; + bool enabled = false; - if (kstrtobool(buf, &enabled)) { - GOOG_ERR("error: invalid input!\n"); + if (kstrtou32(buf, 10, &fw_grip_mode)) { + GOOG_INFO(gti, "error: invalid input!\n"); return size; } - gti->cmd.irq_cmd.setting = enabled; - ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_IRQ_MODE); + enabled = fw_grip_mode & 0x01; + gti->ignore_grip_update = (fw_grip_mode >> 1) & 0x01; + gti->cmd.grip_cmd.setting = enabled ? GTI_GRIP_ENABLE : GTI_GRIP_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_GRIP_MODE); if (ret == -EOPNOTSUPP) - GOOG_LOG("error: not supported!\n"); + GOOG_INFO(gti, "error: not supported!\n"); else if (ret) - GOOG_LOG("error: %d!\n", ret); + GOOG_INFO(gti, "error: %d!\n", ret); else - GOOG_LOG("irq_enabled= %u\n", gti->cmd.irq_cmd.setting); + GOOG_INFO(gti, "fw_grip_mode: %u\n", fw_grip_mode); return size; } -static ssize_t mf_mode_show(struct device *dev, +static ssize_t fw_palm_show(struct device *dev, struct device_attribute *attr, char *buf) { + int ret = 0; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); + struct gti_palm_cmd *cmd = >i->cmd.palm_cmd; - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %u\n", gti->mf_mode); - GOOG_LOG("%s", buf); + cmd->setting = GTI_PALM_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_PALM_MODE); + if (ret == -EOPNOTSUPP) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "error: not supported!\n"); + } else if (ret) { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "error: %d!\n", ret); + } else { + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", cmd->setting | (gti->ignore_palm_update << 1)); + } + GOOG_INFO(gti, "%s", buf); return buf_idx; } -static ssize_t mf_mode_store(struct device *dev, +static ssize_t fw_palm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { + int ret = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - enum gti_mf_mode mode = 0; - - if (buf == NULL || size < 0) { - GOOG_LOG("error: invalid input!\n"); - return size; - } - - if (kstrtou32(buf, 10, &mode)) { - GOOG_LOG("error: invalid input!\n"); - return size; - } + int fw_palm_mode; + bool enabled; - if (mode < GTI_MF_MODE_UNFILTER || - mode > GTI_MF_MODE_AUTO_REPORT) { - GOOG_LOG("error: invalid input!\n"); - return size; + if (kstrtou32(buf, 10, &fw_palm_mode)) { + GOOG_INFO(gti, "error: invalid input!\n"); + return -EINVAL; } - gti->mf_mode = mode; - GOOG_LOG("mf_mode= %u\n", gti->mf_mode); + enabled = fw_palm_mode & 0x01; + gti->ignore_palm_update = (fw_palm_mode >> 1) & 0x01; + gti->cmd.palm_cmd.setting = enabled ? GTI_PALM_ENABLE : GTI_PALM_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_PALM_MODE); + if (ret == -EOPNOTSUPP) + GOOG_INFO(gti, "error: not supported!\n"); + else if (ret) + GOOG_INFO(gti, "error: %d!\n", ret); + else + GOOG_INFO(gti, "fw_palm_mode= %u\n", fw_palm_mode); return size; } -static ssize_t ms_base_show(struct device *dev, +static ssize_t fw_ver_show(struct device *dev, struct device_attribute *attr, char *buf) { + int ret; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - cmd->type = GTI_SENSOR_DATA_TYPE_MS_BASELINE; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + memset(gti->cmd.fw_version_cmd.buffer, 0, sizeof(gti->cmd.fw_version_cmd.buffer)); + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_FW_VERSION); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\n"); - } - GOOG_LOG("%s", buf); - } + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %s\n", gti->cmd.fw_version_cmd.buffer); } + GOOG_INFO(gti, "%s", buf); + return buf_idx; } -static ssize_t ms_diff_show(struct device *dev, +static ssize_t irq_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { + int ret; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - cmd->type = GTI_SENSOR_DATA_TYPE_MS_DIFF; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + gti->cmd.irq_cmd.setting = GTI_IRQ_MODE_NA; + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_IRQ_MODE); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\n"); - } - GOOG_LOG("%s", buf); - } + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", gti->cmd.irq_cmd.setting); } + GOOG_INFO(gti, "%s", buf); + return buf_idx; } -static ssize_t ms_raw_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t irq_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) { - ssize_t buf_idx = 0; + int ret; + bool enabled; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - cmd->type = GTI_SENSOR_DATA_TYPE_MS_RAW; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - for (y = 0; y < rx; y++) { - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[y * tx + x]); - } - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\n"); - } - GOOG_LOG("%s", buf); - } + if (kstrtobool(buf, &enabled)) { + GOOG_ERR(gti, "error: invalid input!\n"); + return size; } - return buf_idx; + + gti->cmd.irq_cmd.setting = enabled; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_IRQ_MODE); + if (ret == -EOPNOTSUPP) + GOOG_INFO(gti, "error: not supported!\n"); + else if (ret) + GOOG_INFO(gti, "error: %d!\n", ret); + else + GOOG_INFO(gti, "irq_enabled= %u\n", gti->cmd.irq_cmd.setting); + + return size; } -static ssize_t offload_enabled_show(struct device *dev, +static ssize_t mf_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %d\n", gti->offload_enable); - GOOG_LOG("%s", buf); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %u\n", gti->mf_mode); + GOOG_INFO(gti, "%s", buf); return buf_idx; } -static ssize_t offload_enabled_store(struct device *dev, +static ssize_t mf_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct goog_touch_interface *gti = dev_get_drvdata(dev); + enum gti_mf_mode mode = 0; - if (kstrtobool(buf, >i->offload_enable)) { - GOOG_LOG("error: invalid input!\n"); - } else { - GOOG_LOG("offload_enable= %d\n", gti->offload_enable); - /* Force to turn off offload by request. */ - if (!gti->offload_enable) - goog_offload_set_running(gti, false); + if (buf == NULL || size < 0) { + GOOG_INFO(gti, "error: invalid input!\n"); + return size; } + if (kstrtou32(buf, 10, &mode)) { + GOOG_INFO(gti, "error: invalid input!\n"); + return size; + } + + if (mode < GTI_MF_MODE_UNFILTER || + mode > GTI_MF_MODE_AUTO_REPORT) { + GOOG_INFO(gti, "error: invalid input!\n"); + return size; + } + + gti->mf_mode = mode; + GOOG_INFO(gti, "mf_mode= %u\n", gti->mf_mode); + return size; } -static ssize_t palm_enabled_show(struct device *dev, +static ssize_t offload_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { - int ret = 0; ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_palm_cmd *cmd = >i->cmd.palm_cmd; - cmd->setting = GTI_PALM_DISABLE; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_PALM_MODE); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %u\n", cmd->setting); - } - GOOG_LOG("%s", buf); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %d\n", gti->offload_enabled); + GOOG_INFO(gti, "%s", buf); return buf_idx; } -static ssize_t palm_enabled_store(struct device *dev, +static ssize_t offload_enabled_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int ret = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_palm_cmd *cmd = >i->cmd.palm_cmd; - bool enabled = false; - if (kstrtobool(buf, &enabled)) { - GOOG_LOG("error: invalid input!\n"); - return -EINVAL; + if (kstrtobool(buf, >i->offload_enabled)) { + GOOG_INFO(gti, "error: invalid input!\n"); + } else { + GOOG_INFO(gti, "offload_enabled= %d\n", gti->offload_enabled); + /* Force to turn off offload by request. */ + if (!gti->offload_enabled) + goog_offload_set_running(gti, false); } - cmd->setting = enabled ? GTI_PALM_ENABLE : GTI_PALM_DISABLE; - ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_PALM_MODE); - if (ret == -EOPNOTSUPP) - GOOG_LOG("error: not supported!\n"); - else if (ret) - GOOG_LOG("error: %d!\n", ret); - else - GOOG_LOG("palm_enabled= %u\n", cmd->setting); - return size; } @@ -549,18 +807,18 @@ static ssize_t ping_show(struct device *dev, gti->cmd.ping_cmd.setting = GTI_PING_ENABLE; ret = goog_process_vendor_cmd(gti, GTI_CMD_PING); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); gti->cmd.ping_cmd.setting = GTI_PING_NA; } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); gti->cmd.ping_cmd.setting = GTI_PING_NA; } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result: success.\n"); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } @@ -573,13 +831,13 @@ static ssize_t reset_show(struct device *dev, if (gti->cmd.reset_cmd.setting == GTI_RESET_MODE_NOP || gti->cmd.reset_cmd.setting == GTI_RESET_MODE_NA) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", gti->cmd.reset_cmd.setting); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result: success.\n"); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } @@ -592,31 +850,31 @@ static ssize_t reset_store(struct device *dev, enum gti_reset_mode mode = 0; if (buf == NULL || size < 0) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } if (kstrtou32(buf, 10, &mode)) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } if (mode <= GTI_RESET_MODE_NOP || mode > GTI_RESET_MODE_AUTO) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return -EINVAL; } gti->cmd.reset_cmd.setting = mode; ret = goog_process_vendor_cmd(gti, GTI_CMD_RESET); if (ret == -EOPNOTSUPP) { - GOOG_LOG("error: not supported!\n"); + GOOG_INFO(gti, "error: not supported!\n"); gti->cmd.reset_cmd.setting = GTI_RESET_MODE_NA; } else if (ret) { - GOOG_LOG("error: %d!\n", ret); + GOOG_INFO(gti, "error: %d!\n", ret); gti->cmd.reset_cmd.setting = GTI_RESET_MODE_NA; } else { - GOOG_LOG("reset= 0x%x\n", mode); + GOOG_INFO(gti, "reset= 0x%x\n", mode); } return size; @@ -632,16 +890,16 @@ static ssize_t scan_mode_show(struct device *dev, gti->cmd.scan_cmd.setting = GTI_SCAN_MODE_NA; ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SCAN_MODE); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result: %u\n", gti->cmd.scan_cmd.setting); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } @@ -654,29 +912,29 @@ static ssize_t scan_mode_store(struct device *dev, enum gti_scan_mode mode = 0; if (buf == NULL || size < 0) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return size; } if (kstrtou32(buf, 10, &mode)) { - GOOG_ERR("error: invalid input!\n"); + GOOG_ERR(gti, "error: invalid input!\n"); return size; } if (mode < GTI_SCAN_MODE_AUTO || mode > GTI_SCAN_MODE_LP_IDLE) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return size; } gti->cmd.scan_cmd.setting = mode; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_SCAN_MODE); if (ret == -EOPNOTSUPP) - GOOG_ERR("error: not supported!\n"); + GOOG_ERR(gti, "error: not supported!\n"); else if (ret) - GOOG_ERR("error: %d!\n", ret); + GOOG_ERR(gti, "error: %d!\n", ret); else - GOOG_LOG("scan_mode= %u\n", mode); + GOOG_INFO(gti, "scan_mode= %u\n", mode); return size; } @@ -690,18 +948,18 @@ static ssize_t screen_protector_mode_enabled_store(struct device *dev, bool enabled = false; if (kstrtobool(buf, &enabled)) { - GOOG_ERR("invalid input!\n"); + GOOG_ERR(gti, "invalid input!\n"); return -EINVAL; } cmd->setting = enabled ? GTI_SCREEN_PROTECTOR_MODE_ENABLE : GTI_SCREEN_PROTECTOR_MODE_DISABLE; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_SCREEN_PROTECTOR_MODE); if (ret == -EOPNOTSUPP) - GOOG_ERR("error: not supported!\n"); + GOOG_ERR(gti, "error: not supported!\n"); else if (ret) - GOOG_ERR("error: %d!\n", ret); + GOOG_ERR(gti, "error: %d!\n", ret); else - GOOG_LOG("enabled= %u\n", enabled); + GOOG_INFO(gti, "enabled= %u\n", enabled); gti->screen_protector_mode_setting = enabled ? GTI_SCREEN_PROTECTOR_MODE_ENABLE : GTI_SCREEN_PROTECTOR_MODE_DISABLE; return size; @@ -711,20 +969,20 @@ static ssize_t screen_protector_mode_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret = 0; - size_t size = 0; + ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); struct gti_screen_protector_mode_cmd *cmd = >i->cmd.screen_protector_mode_cmd; cmd->setting = GTI_SCREEN_PROTECTOR_MODE_NA; ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SCREEN_PROTECTOR_MODE); if (ret == 0) { - size += scnprintf(buf, PAGE_SIZE, "result: %d\n", + buf_idx += scnprintf(buf, PAGE_SIZE - buf_idx, "result: %d\n", cmd->setting == GTI_SCREEN_PROTECTOR_MODE_ENABLE); } else { - size += scnprintf(buf, PAGE_SIZE, "error: %d\n", ret); + buf_idx += scnprintf(buf, PAGE_SIZE - buf_idx, "error: %d\n", ret); } - GOOG_LOG("%s", buf); - return size; + GOOG_INFO(gti, "%s", buf); + return buf_idx; } static ssize_t self_test_show(struct device *dev, @@ -738,151 +996,25 @@ static ssize_t self_test_show(struct device *dev, memset(gti->cmd.selftest_cmd.buffer, 0, sizeof(gti->cmd.selftest_cmd.buffer)); ret = goog_process_vendor_cmd(gti, GTI_CMD_SELFTEST); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { if (gti->cmd.selftest_cmd.result == GTI_SELFTEST_RESULT_DONE) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result: %s\n", gti->cmd.selftest_cmd.buffer); } else if (gti->cmd.selftest_cmd.result == GTI_SELFTEST_RESULT_SHELL_CMDS_REDIRECT) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "redirect: %s\n", gti->cmd.selftest_cmd.buffer); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "error: N/A!\n"); - } - } - GOOG_LOG("%s", buf); - - return buf_idx; -} - -static ssize_t ss_base_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_BASELINE; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - GOOG_LOG("%s", buf); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: N/A!\n"); } } - return buf_idx; -} - -static ssize_t ss_diff_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_DIFF; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - GOOG_LOG("%s", buf); - } - } - return buf_idx; -} + GOOG_INFO(gti, "%s", buf); -static ssize_t ss_raw_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t buf_idx = 0; - struct goog_touch_interface *gti = dev_get_drvdata(dev); - struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; - int ret = 0; - u16 tx = gti->offload.caps.tx_size; - u16 rx = gti->offload.caps.rx_size; - int x, y; - - cmd->type = GTI_SENSOR_DATA_TYPE_SS_RAW; - cmd->buffer = NULL; - cmd->size = 0; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); - if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: not supported!\n"); - } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "error: %d!\n", ret); - } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "result:\n"); - if (cmd->buffer && - cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "TX:"); - for (x = 0; x < tx; x++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[x]); - } - - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, "\nRX:"); - for (y = 0; y < rx; y++) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "%5d,", ((s16 *)cmd->buffer)[tx + y]); - } - GOOG_LOG("%s", buf); - } - } return buf_idx; } @@ -896,16 +1028,16 @@ static ssize_t sensing_enabled_show(struct device *dev, gti->cmd.sensing_cmd.setting = GTI_SENSING_MODE_NA; ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSING_MODE); if (ret == -EOPNOTSUPP) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: not supported!\n"); } else if (ret) { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "error: %d!\n", ret); } else { - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, "result: %u\n", gti->cmd.sensing_cmd.setting); } - GOOG_LOG("%s", buf); + GOOG_INFO(gti, "%s", buf); return buf_idx; } @@ -918,18 +1050,18 @@ static ssize_t sensing_enabled_store(struct device *dev, struct goog_touch_interface *gti = dev_get_drvdata(dev); if (kstrtobool(buf, &enabled)) { - GOOG_LOG("error: invalid input!\n"); + GOOG_INFO(gti, "error: invalid input!\n"); return size; } gti->cmd.sensing_cmd.setting = enabled; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_SENSING_MODE); if (ret == -EOPNOTSUPP) - GOOG_LOG("error: not supported!\n"); + GOOG_INFO(gti, "error: not supported!\n"); else if (ret) - GOOG_LOG("error: %d!\n", ret); + GOOG_INFO(gti, "error: %d!\n", ret); else - GOOG_LOG("sensing_enabled= %u\n", gti->cmd.sensing_cmd.setting); + GOOG_INFO(gti, "sensing_enabled= %u\n", gti->cmd.sensing_cmd.setting); return size; } @@ -940,9 +1072,9 @@ static ssize_t v4l2_enabled_show(struct device *dev, ssize_t buf_idx = 0; struct goog_touch_interface *gti = dev_get_drvdata(dev); - buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, - "result: %d\n", gti->v4l2_enable); - GOOG_LOG("%s", buf); + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE - buf_idx, + "result: %d\n", gti->v4l2_enabled); + GOOG_INFO(gti, "%s", buf); return buf_idx; } @@ -952,10 +1084,41 @@ static ssize_t v4l2_enabled_store(struct device *dev, { struct goog_touch_interface *gti = dev_get_drvdata(dev); - if (kstrtobool(buf, >i->v4l2_enable)) - GOOG_LOG("error: invalid input!\n"); + if (kstrtobool(buf, >i->v4l2_enabled)) + GOOG_INFO(gti, "error: invalid input!\n"); else - GOOG_LOG("v4l2_enable= %d\n", gti->v4l2_enable); + GOOG_INFO(gti, "v4l2_enabled= %d\n", gti->v4l2_enabled); + + return size; +} + +static ssize_t vrr_enabled_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t buf_idx = 0; + struct goog_touch_interface *gti = dev_get_drvdata(dev); + + buf_idx += scnprintf(buf + buf_idx, PAGE_SIZE, + "result: %d\n", gti->vrr_enabled); + GOOG_INFO(gti, "%s", buf); + + return buf_idx; +} + +static ssize_t vrr_enabled_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct goog_touch_interface *gti = dev_get_drvdata(dev); + + if (kstrtobool(buf, >i->vrr_enabled)) { + GOOG_INFO(gti, "error: invalid input!\n"); + } else if (gti->report_rate_table_size == 0) { + GOOG_INFO(gti, "error: No valid report rate table!\n"); + } else { + GOOG_INFO(gti, "vrr_enabled= %d\n", gti->vrr_enabled); + if (gti->vrr_enabled) + goog_lookup_touch_report_rate(gti); + } return size; } @@ -964,12 +1127,80 @@ static ssize_t v4l2_enabled_store(struct device *dev, * Debug: functions. */ #ifdef GTI_DEBUG_KFIFO_LEN +inline void gti_debug_hc_push(struct goog_touch_interface *gti) +{ + /* + * Use kfifo as circular buffer by skipping one element + * when fifo is full. + */ + if (kfifo_is_full(>i->debug_fifo_hc)) + kfifo_skip(>i->debug_fifo_hc); + kfifo_in(>i->debug_fifo_hc, >i->debug_hc, 1); +} + +inline int gti_debug_hc_pop(struct goog_touch_interface *gti, + struct gti_debug_health_check *fifo, unsigned int len) +{ + if (len > GTI_DEBUG_KFIFO_LEN) { + GOOG_ERR(gti, "invalid fifo pop len(%d)!\n", len); + return -EINVAL; + } + /* + * Keep data without pop-out to support different timing + * print-out by each caller. + */ + return kfifo_out_peek(>i->debug_fifo_hc, fifo, len) == len ? 0 : -EFAULT; +} + +inline void gti_debug_hc_update(struct goog_touch_interface *gti, bool from_top_half) +{ + if (from_top_half) { + gti->debug_hc.irq_time = ktime_get(); + gti->debug_hc.irq_index = gti->irq_index; + } else { + gti->debug_hc.input_index = gti->input_index; + gti->debug_hc.slot_bit_active = gti->slot_bit_active; + gti_debug_hc_push(gti); + } +} + +void gti_debug_hc_dump(struct goog_touch_interface *gti) +{ + int ret; + u64 i, count; + s64 delta; + s64 sec_delta; + u32 ms_delta; + ktime_t current_time = ktime_get(); + struct gti_debug_health_check last_fifo[GTI_DEBUG_KFIFO_LEN] = { 0 }; + + count = min_t(u64, gti->irq_index, ARRAY_SIZE(last_fifo)); + ret = gti_debug_hc_pop(gti, last_fifo, count); + if (ret) { + GOOG_ERR(gti, "Failed to peek debug hc, err: %d\n", ret); + return; + } + for (i = 0 ; i < count ; i++) { + sec_delta = -1; + ms_delta = 0; + /* + * Calculate the delta time between irq triggered and current time. + */ + delta = ktime_ms_delta(current_time, last_fifo[i].irq_time); + if (delta > 0) + sec_delta = div_u64_rem(delta, MSEC_PER_SEC, &ms_delta); + GOOG_LOG(gti, "dump-int: #%llu(%lld.%u): C#%llu(0x%lx).\n", + last_fifo[i].irq_index, sec_delta, ms_delta, + last_fifo[i].input_index, last_fifo[i].slot_bit_active); + } +} + inline void gti_debug_input_push(struct goog_touch_interface *gti, int slot) { struct gti_debug_input fifo; if (slot < 0 || slot >= MAX_SLOTS) { - GOOG_ERR("Invalid slot: %d\n", slot); + GOOG_ERR(gti, "Invalid slot: %d\n", slot); return; } @@ -977,18 +1208,18 @@ inline void gti_debug_input_push(struct goog_touch_interface *gti, int slot) * Use kfifo as circular buffer by skipping one element * when fifo is full. */ - if (kfifo_is_full(>i->debug_fifo)) - kfifo_skip(>i->debug_fifo); + if (kfifo_is_full(>i->debug_fifo_input)) + kfifo_skip(>i->debug_fifo_input); memcpy(&fifo, >i->debug_input[slot], sizeof(struct gti_debug_input)); - kfifo_in(>i->debug_fifo, &fifo, 1); + kfifo_in(>i->debug_fifo_input, &fifo, 1); } inline int gti_debug_input_pop(struct goog_touch_interface *gti, struct gti_debug_input *fifo, unsigned int len) { if (len > GTI_DEBUG_KFIFO_LEN) { - GOOG_ERR("invalid fifo pop len(%d)!\n", len); + GOOG_ERR(gti, "invalid fifo pop len(%d)!\n", len); return -EINVAL; } @@ -996,23 +1227,26 @@ inline int gti_debug_input_pop(struct goog_touch_interface *gti, * Keep coords without pop-out to support different timing * print-out by each caller. */ - return kfifo_out_peek(>i->debug_fifo, fifo, len) == len ? 0 : -EFAULT; + return kfifo_out_peek(>i->debug_fifo_input, fifo, len) == len ? 0 : -EFAULT; } inline void gti_debug_input_update(struct goog_touch_interface *gti) { int slot; + u64 irq_index = gti->irq_index; ktime_t time = ktime_get(); for_each_set_bit(slot, >i->slot_bit_changed, MAX_SLOTS) { if (test_bit(slot, >i->slot_bit_active)) { gti->debug_input[slot].pressed.time = time; + gti->debug_input[slot].pressed.irq_index = irq_index; memcpy(>i->debug_input[slot].pressed.coord, >i->offload.coords[slot], sizeof(struct TouchOffloadCoord)); } else { - gti->released_count++; + gti->released_index++; gti->debug_input[slot].released.time = time; + gti->debug_input[slot].released.irq_index = irq_index; memcpy(>i->debug_input[slot].released.coord, >i->offload.coords[slot], sizeof(struct TouchOffloadCoord)); @@ -1024,8 +1258,8 @@ inline void gti_debug_input_update(struct goog_touch_interface *gti) void gti_debug_input_dump(struct goog_touch_interface *gti) { - int ret = 0; - int i, slot, count; + int slot, ret; + u64 i, count; s64 delta; s64 sec_delta_down; u32 ms_delta_down; @@ -1035,17 +1269,16 @@ void gti_debug_input_dump(struct goog_touch_interface *gti) ktime_t current_time = ktime_get(); struct gti_debug_input last_fifo[GTI_DEBUG_KFIFO_LEN] = { 0 }; - count = min(gti->released_count, ARRAY_SIZE(last_fifo)); + count = min_t(u64, gti->released_index, ARRAY_SIZE(last_fifo)); ret = gti_debug_input_pop(gti, last_fifo, count); - if (ret != 0) { - GOOG_ERR("Failed to peek debug input, err: %d\n", ret); + if (ret) { + GOOG_ERR(gti, "Failed to peek debug input, err: %d\n", ret); return; } - for (i = 0 ; i < count ; i++) { if (last_fifo[i].slot < 0 || last_fifo[i].slot >= MAX_SLOTS) { - GOOG_LOG("dump: #%d: invalid slot #!\n", last_fifo[i].slot); + GOOG_INFO(gti, "dump: #%d: invalid slot #!\n", last_fifo[i].slot); continue; } sec_delta_down = -1; @@ -1077,19 +1310,21 @@ void gti_debug_input_dump(struct goog_touch_interface *gti) last_fifo[i].pressed.coord.y; } } - GOOG_LOG("dump: #%d: %lld.%u(%lld.%u) D(%d, %d).\n", + + GOOG_LOG(gti, "dump: #%d: %lld.%u(%lld.%u) D(%d, %d) I(%llu, %llu).\n", last_fifo[i].slot, sec_delta_down, ms_delta_down, sec_delta_duration, ms_delta_duration, - px_delta_x, px_delta_y); - GOOG_DBG("dump-dbg: #%d: P(%u, %u) -> R(%u, %u).\n\n", + px_delta_x, px_delta_y, + last_fifo[i].pressed.irq_index, last_fifo[i].released.irq_index); + GOOG_DBG(gti, "dump-dbg: #%d: P(%u, %u) -> R(%u, %u).\n\n", last_fifo[i].slot, last_fifo[i].pressed.coord.x, last_fifo[i].pressed.coord.y, last_fifo[i].released.coord.x, last_fifo[i].released.coord.y); } /* Extra check for unexpected case. */ for_each_set_bit(slot, >i->slot_bit_active, MAX_SLOTS) { - GOOG_LOG("slot #%d is not released after suspend!\n", slot); + GOOG_INFO(gti, "slot #%d is active!\n", slot); } } #endif /* GTI_DEBUG_KFIFO_LEN */ @@ -1099,28 +1334,19 @@ void gti_debug_input_dump(struct goog_touch_interface *gti) */ static void panel_bridge_enable(struct drm_bridge *bridge) { - int ret = 0; struct goog_touch_interface *gti = container_of(bridge, struct goog_touch_interface, panel_bridge); if (gti->panel_is_lp_mode) { - GOOG_LOG("skip screen-on because of panel_is_lp_mode enabled!\n"); + GOOG_DBG(gti, "skip screen-on because of panel_is_lp_mode enabled!\n"); return; } - GOOG_LOG("screen-on.\n"); - - goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON, false); - - gti->cmd.display_state_cmd.setting = GTI_DISPLAY_STATE_ON; - ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_STATE); - if (ret && ret != -EOPNOTSUPP) - GOOG_WARN("unexpected vendor_cmd return(%d)!\n", ret); + goog_set_display_state(gti, GTI_DISPLAY_STATE_ON); } static void panel_bridge_disable(struct drm_bridge *bridge) { - int ret = 0; struct goog_touch_interface *gti = container_of(bridge, struct goog_touch_interface, panel_bridge); @@ -1131,14 +1357,7 @@ static void panel_bridge_disable(struct drm_bridge *bridge) return; } - GOOG_LOG("screen-off.\n"); - - goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON); - - gti->cmd.display_state_cmd.setting = GTI_DISPLAY_STATE_OFF; - ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_STATE); - if (ret && ret != -EOPNOTSUPP) - GOOG_WARN("unexpected vendor_cmd return(%d)!\n", ret); + goog_set_display_state(gti, GTI_DISPLAY_STATE_OFF); } struct drm_connector *get_bridge_connector(struct drm_bridge *bridge) @@ -1180,19 +1399,13 @@ static void panel_bridge_mode_set(struct drm_bridge *bridge, panel_is_lp_mode = panel_bridge_is_lp_mode(gti->connector); if (gti->panel_is_lp_mode != panel_is_lp_mode) { - - GOOG_LOG("panel_is_lp_mode changed from %d to %d.\n", + GOOG_INFO(gti, "panel_is_lp_mode changed from %d to %d.\n", gti->panel_is_lp_mode, panel_is_lp_mode); - if (panel_is_lp_mode) { - goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON); - gti->cmd.display_state_cmd.setting = GTI_DISPLAY_STATE_OFF; - } else { - goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON, false); - gti->cmd.display_state_cmd.setting = GTI_DISPLAY_STATE_ON; - } - ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_STATE); - if (ret && ret != -EOPNOTSUPP) - GOOG_WARN("unexpected return(%d)!", ret); + + if (panel_is_lp_mode) + goog_set_display_state(gti, GTI_DISPLAY_STATE_OFF); + else + goog_set_display_state(gti, GTI_DISPLAY_STATE_ON); } gti->panel_is_lp_mode = panel_is_lp_mode; @@ -1200,13 +1413,17 @@ static void panel_bridge_mode_set(struct drm_bridge *bridge, int vrefresh = drm_mode_vrefresh(mode); if (gti->display_vrefresh != vrefresh) { - GOOG_DBG("display_vrefresh(Hz) changed to %d from %d.\n", + GOOG_DBG(gti, "display_vrefresh(Hz) changed to %d from %d.\n", vrefresh, gti->display_vrefresh); gti->display_vrefresh = vrefresh; gti->cmd.display_vrefresh_cmd.setting = vrefresh; + gti->context_changed.display_refresh_rate = 1; ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_VREFRESH); if (ret && ret != -EOPNOTSUPP) - GOOG_WARN("unexpected return(%d)!", ret); + GOOG_WARN(gti, "unexpected return(%d)!", ret); + + if (gti->vrr_enabled) + goog_lookup_touch_report_rate(gti); } } } @@ -1219,7 +1436,7 @@ static const struct drm_bridge_funcs panel_bridge_funcs = { static int register_panel_bridge(struct goog_touch_interface *gti) { - GOOG_LOG("\n"); + GOOG_INFO(gti, "\n"); #ifdef CONFIG_OF gti->panel_bridge.of_node = gti->vendor_dev->of_node; #endif @@ -1231,9 +1448,11 @@ static int register_panel_bridge(struct goog_touch_interface *gti) static void unregister_panel_bridge(struct drm_bridge *bridge) { + struct goog_touch_interface *gti = + container_of(bridge, struct goog_touch_interface, panel_bridge); struct drm_bridge *node; - GOOG_LOG("\n"); + GOOG_INFO(gti, "\n"); drm_bridge_remove(bridge); if (!bridge->dev) /* not attached */ @@ -1255,6 +1474,77 @@ static void unregister_panel_bridge(struct drm_bridge *bridge) /*----------------------------------------------------------------------------- * GTI: functions. */ +static int goog_precheck_heatmap(struct goog_touch_interface *gti) +{ + int ret = 0; + + /* + * Check the PM wakelock state and pm state for bus ownership before + * data request. + */ + if (!goog_pm_wake_get_locks(gti) || gti->pm.state == GTI_PM_SUSPEND) { + GOOG_WARN(gti, "N/A during inactive bus!\n"); + ret = -ENODATA; + } + + return ret; +} + +static void goog_set_display_state(struct goog_touch_interface *gti, + enum gti_display_state_setting display_state) +{ + int ret = 0; + + if (gti->display_state == display_state) + return; + + switch (display_state) { + case GTI_DISPLAY_STATE_OFF: + GOOG_INFO(gti, "screen-off.\n"); + ret = goog_pm_wake_unlock_nosync(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON); + if (ret < 0) + GOOG_INFO(gti, "Error while obtaining screen-off wakelock: %d!\n", ret); + + break; + case GTI_DISPLAY_STATE_ON: + GOOG_INFO(gti, "screen-on.\n"); + ret = goog_pm_wake_lock_nosync(gti, GTI_PM_WAKELOCK_TYPE_SCREEN_ON, false); + if (ret < 0) + GOOG_INFO(gti, "Error while obtaining screen-on wakelock: %d!\n", ret); + + break; + default: + GOOG_ERR(gti, "Unexpected value(0x%X) of display state parameter.\n", + display_state); + return; + } + + gti->context_changed.screen_state = 1; + gti->display_state = display_state; + gti->cmd.display_state_cmd.setting = display_state; + ret = goog_process_vendor_cmd(gti, GTI_CMD_NOTIFY_DISPLAY_STATE); + if (ret && ret != -EOPNOTSUPP) + GOOG_WARN(gti, "Unexpected vendor_cmd return(%d)!\n", ret); +} + +bool goog_check_spi_dma_enabled(struct spi_device *spi_dev) +{ + bool ret = false; + + if (spi_dev && spi_dev->controller) { + struct device_node *np = spi_dev->controller->dev.of_node; + + /* + * Check the SPI controller(s3c64xx-spi) whether support DMA + * or not. + */ + ret = of_property_read_bool(np, "dma-mode"); + } + + return ret; +} +EXPORT_SYMBOL(goog_check_spi_dma_enabled); + int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type cmd_type) { void *private_data = gti->vendor_private_data; @@ -1271,6 +1561,16 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type case GTI_CMD_SELFTEST: ret = gti->options.selftest(private_data, >i->cmd.selftest_cmd); break; + case GTI_CMD_GET_CONTEXT_DRIVER: + ret = gti->options.get_context_driver(private_data, >i->cmd.context_driver_cmd); + break; + case GTI_CMD_GET_CONTEXT_STYLUS: + ret = gti->options.get_context_stylus(private_data, >i->cmd.context_stylus_cmd); + break; + case GTI_CMD_GET_COORD_FILTER_ENABLED: + ret = gti->options.get_coord_filter_enabled(private_data, + >i->cmd.coord_filter_cmd); + break; case GTI_CMD_GET_FW_VERSION: ret = gti->options.get_fw_version(private_data, >i->cmd.fw_version_cmd); break; @@ -1302,6 +1602,15 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type private_data, >i->cmd.sensor_data_cmd); } break; + case GTI_CMD_GET_SENSOR_DATA_MANUAL: + if (gti->cmd.manual_sensor_data_cmd.type & TOUCH_SCAN_TYPE_MUTUAL) { + ret = gti->options.get_mutual_sensor_data( + private_data, >i->cmd.manual_sensor_data_cmd); + } else if (gti->cmd.manual_sensor_data_cmd.type & TOUCH_SCAN_TYPE_SELF) { + ret = gti->options.get_self_sensor_data( + private_data, >i->cmd.manual_sensor_data_cmd); + } + break; case GTI_CMD_NOTIFY_DISPLAY_STATE: ret = gti->options.notify_display_state(private_data, >i->cmd.display_state_cmd); @@ -1314,7 +1623,14 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type ret = gti->options.set_continuous_report(private_data, >i->cmd.continuous_report_cmd); break; + case GTI_CMD_SET_COORD_FILTER_ENABLED: + ret = gti->options.set_coord_filter_enabled(private_data, + >i->cmd.coord_filter_cmd); + break; case GTI_CMD_SET_GRIP_MODE: + GOOG_INFO(gti, "Set firmware grip %s", + gti->cmd.grip_cmd.setting == GTI_GRIP_ENABLE ? + "enabled" : "disabled"); ret = gti->options.set_grip_mode(private_data, >i->cmd.grip_cmd); break; case GTI_CMD_SET_HEATMAP_ENABLED: @@ -1324,13 +1640,25 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type ret = gti->options.set_irq_mode(private_data, >i->cmd.irq_cmd); break; case GTI_CMD_SET_PALM_MODE: + GOOG_INFO(gti, "Set firmware palm %s", + gti->cmd.palm_cmd.setting == GTI_PALM_ENABLE ? + "enabled" : "disabled"); ret = gti->options.set_palm_mode(private_data, >i->cmd.palm_cmd); break; + case GTI_CMD_SET_REPORT_RATE: + GOOG_INFO(gti, "Set touch report rate as %d Hz", gti->cmd.report_rate_cmd.setting); + ret = gti->options.set_report_rate(private_data, >i->cmd.report_rate_cmd); + break; case GTI_CMD_SET_SCAN_MODE: ret = gti->options.set_scan_mode(private_data, >i->cmd.scan_cmd); break; case GTI_CMD_SET_SCREEN_PROTECTOR_MODE: - ret = gti->options.set_screen_protector_mode(private_data, >i->cmd.screen_protector_mode_cmd); + GOOG_INFO(gti, "Set screen protector mode %s", + gti->cmd.screen_protector_mode_cmd.setting == + GTI_SCREEN_PROTECTOR_MODE_ENABLE + ? "enabled" : "disabled"); + ret = gti->options.set_screen_protector_mode(private_data, + >i->cmd.screen_protector_mode_cmd); break; case GTI_CMD_SET_SENSING_MODE: ret = gti->options.set_sensing_mode(private_data, >i->cmd.sensing_cmd); @@ -1345,7 +1673,10 @@ int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type /* Take unsupported cmd_type as debug logs for compatibility check. */ if (ret == -EOPNOTSUPP) { - GOOG_DBG("unsupported request cmd_type %#x!\n", cmd_type); + GOOG_DBG(gti, "unsupported request cmd_type %#x!\n", cmd_type); + ret = 0; + } else if (ret == -ESRCH) { + GOOG_WARN(gti, "No handler for cmd_type %#x!\n", cmd_type); ret = 0; } @@ -1410,7 +1741,7 @@ void goog_update_motion_filter(struct goog_touch_interface *gti, unsigned long s ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_CONTINUOUS_REPORT); if (ret) - GOOG_WARN("unexpected return(%d)!", ret); + GOOG_WARN(gti, "unexpected return(%d)!", ret); } gti->mf_state = next_state; @@ -1426,7 +1757,7 @@ bool goog_v4l2_read_frame_cb(struct v4l2_heatmap *v4l2) memcpy(v4l2->frame, gti->heatmap_buf, v4l2_size); ret = true; } else { - GOOG_ERR("wrong pointer(%p) or size (W: %lu, H: %lu) vs %u\n", + GOOG_ERR(gti, "wrong pointer(%p) or size (W: %lu, H: %lu) vs %u\n", gti->heatmap_buf, gti->v4l2.width, gti->v4l2.height, gti->heatmap_buf_size); } @@ -1435,10 +1766,28 @@ bool goog_v4l2_read_frame_cb(struct v4l2_heatmap *v4l2) void goog_v4l2_read(struct goog_touch_interface *gti, ktime_t timestamp) { - if (gti->v4l2_enable) + if (gti->v4l2_enabled) heatmap_read(>i->v4l2, ktime_to_ns(timestamp)); } +int goog_get_driver_status(struct goog_touch_interface *gti, + struct gti_context_driver_cmd *driver_cmd) +{ + gti->context_changed.offload_timestamp = 1; + + driver_cmd->context_changed.value = gti->context_changed.value; + driver_cmd->screen_state = gti->display_state; + driver_cmd->display_refresh_rate = gti->display_vrefresh; + driver_cmd->touch_report_rate = gti->report_rate_setting; + driver_cmd->noise_state = gti->fw_status.noise_level; + driver_cmd->water_mode = gti->fw_status.water_mode; + driver_cmd->charger_state = gti->charger_state; + driver_cmd->offload_timestamp = ktime_get(); + + /* vendor driver overwrite the context */ + return goog_process_vendor_cmd(gti, GTI_CMD_GET_CONTEXT_DRIVER); +} + void goog_offload_populate_coordinate_channel(struct goog_touch_interface *gti, struct touch_offload_frame *frame, int channel) { @@ -1446,7 +1795,7 @@ void goog_offload_populate_coordinate_channel(struct goog_touch_interface *gti, struct TouchOffloadDataCoord *dc; if (channel < 0 || channel >= MAX_CHANNELS) { - GOOG_ERR("Invalid channel: %d\n", channel); + GOOG_ERR(gti, "Invalid channel: %d\n", channel); return; } @@ -1472,7 +1821,7 @@ void goog_offload_populate_mutual_channel(struct goog_touch_interface *gti, struct TouchOffloadData2d *mutual; if (channel < 0 || channel >= MAX_CHANNELS) { - GOOG_ERR("Invalid channel: %d\n", channel); + GOOG_ERR(gti, "Invalid channel: %d\n", channel); return; } @@ -1492,7 +1841,7 @@ void goog_offload_populate_self_channel(struct goog_touch_interface *gti, struct TouchOffloadData1d *self; if (channel < 0 || channel >= MAX_CHANNELS) { - GOOG_ERR("Invalid channel: %d\n", channel); + GOOG_ERR(gti, "Invalid channel: %d\n", channel); return; } @@ -1506,10 +1855,114 @@ void goog_offload_populate_self_channel(struct goog_touch_interface *gti, memcpy(self->data, buffer, size); } +static void goog_offload_populate_driver_status_channel( + struct goog_touch_interface *gti, + struct touch_offload_frame *frame, int channel, + struct gti_context_driver_cmd *driver_cmd) +{ + struct TouchOffloadDriverStatus *ds = + (struct TouchOffloadDriverStatus *)frame->channel_data[channel]; + + memset(ds, 0, frame->channel_data_size[channel]); + ds->header.channel_type = (u32)CONTEXT_CHANNEL_TYPE_DRIVER_STATUS; + ds->header.channel_size = sizeof(struct TouchOffloadDriverStatus); + + ds->contents.screen_state = driver_cmd->context_changed.screen_state; + ds->screen_state = driver_cmd->screen_state; + + ds->contents.display_refresh_rate = driver_cmd->context_changed.display_refresh_rate; + ds->display_refresh_rate = driver_cmd->display_refresh_rate; + + ds->contents.touch_report_rate = driver_cmd->context_changed.touch_report_rate; + ds->touch_report_rate = driver_cmd->touch_report_rate; + + ds->contents.noise_state = driver_cmd->context_changed.noise_state; + ds->noise_state = driver_cmd->noise_state; + + ds->contents.water_mode = driver_cmd->context_changed.water_mode; + ds->water_mode = driver_cmd->water_mode; + + ds->contents.charger_state = driver_cmd->context_changed.charger_state; + ds->charger_state = driver_cmd->charger_state; + + ds->contents.offload_timestamp = driver_cmd->context_changed.offload_timestamp; + ds->offload_timestamp = driver_cmd->offload_timestamp; +} + +static void goog_offload_populate_stylus_status_channel( + struct goog_touch_interface *gti, + struct touch_offload_frame *frame, int channel, + struct gti_context_stylus_cmd *stylus_cmd) +{ + struct TouchOffloadStylusStatus *ss = + (struct TouchOffloadStylusStatus *)frame->channel_data[channel]; + + memset(ss, 0, frame->channel_data_size[channel]); + ss->header.channel_type = (u32)CONTEXT_CHANNEL_TYPE_STYLUS_STATUS; + ss->header.channel_size = sizeof(struct TouchOffloadStylusStatus); + + ss->contents.coords = stylus_cmd->contents.coords; + ss->coords[0] = stylus_cmd->pen_offload_coord; + + ss->contents.coords_timestamp = stylus_cmd->contents.coords_timestamp; + ss->coords_timestamp = stylus_cmd->pen_offload_coord_timestamp; + + ss->contents.pen_paired = stylus_cmd->contents.pen_paired; + ss->pen_paired = stylus_cmd->pen_paired; + + ss->contents.pen_active = stylus_cmd->contents.pen_active; + ss->pen_active = stylus_cmd->pen_active; +} + +static int goog_get_sensor_data(struct goog_touch_interface *gti, + struct gti_sensor_data_cmd *cmd, bool reset_data) +{ + int ret = 0; + int err = 0; + u16 tx = gti->offload.caps.tx_size; + u16 rx = gti->offload.caps.rx_size; + + if (reset_data) { + if (cmd->type == GTI_SENSOR_DATA_TYPE_MS) { + cmd->size = TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx); + } else if (cmd->type == GTI_SENSOR_DATA_TYPE_SS) { + cmd->size = TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx); + } else { + ret = -EINVAL; + goto exit; + } + + memset(gti->heatmap_buf, 0, cmd->size); + cmd->buffer = gti->heatmap_buf; + goto exit; + } + + err = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_SENSOR_DATA, true); + if (err < 0) { + GOOG_WARN(gti, "Failed to lock GTI_PM_WAKELOCK_TYPE_SENSOR_DATA: %d!\n", err); + ret = err; + goto exit; + } + + err = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + if (err < 0) { + GOOG_WARN(gti, "Failed to get sensor data: %d!\n", err); + ret = err; + } + + err = goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_SENSOR_DATA); + if (err < 0) + GOOG_WARN(gti, "Failed to unlock GTI_PM_WAKELOCK_TYPE_SENSOR_DATA: %d!\n", err); + +exit: + return ret; +} + void goog_offload_populate_frame(struct goog_touch_interface *gti, - struct touch_offload_frame *frame) + struct touch_offload_frame *frame, bool reset_data) { static u64 index; + char trace_tag[128]; u32 channel_type; int i; int ret; @@ -1517,11 +1970,13 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, u16 rx = gti->offload.caps.rx_size; struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; + scnprintf(trace_tag, sizeof(trace_tag), "%s: IDX=%llu IN_TS=%lld.\n", + __func__, index, gti->input_timestamp); + ATRACE_BEGIN(trace_tag); + frame->header.index = index++; frame->header.timestamp = gti->input_timestamp; - ATRACE_BEGIN(__func__); - /* * TODO(b/201610482): * Porting for other channels, like driver status, stylus status @@ -1531,18 +1986,35 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, /* Populate all channels */ for (i = 0; i < frame->num_channels; i++) { channel_type = frame->channel_type[i]; - GOOG_DBG("#%d: get data(type %#x) from vendor driver", i, channel_type); + GOOG_DBG(gti, "#%d: get data(type %#x) from vendor driver", i, channel_type); ret = 0; cmd->buffer = NULL; cmd->size = 0; - if (channel_type == TOUCH_DATA_TYPE_COORD) { + if (channel_type == CONTEXT_CHANNEL_TYPE_DRIVER_STATUS) { + ATRACE_BEGIN("populate driver context"); + ret = goog_get_driver_status(gti, >i->cmd.context_driver_cmd); + if (ret == 0) + goog_offload_populate_driver_status_channel( + gti, frame, i, + >i->cmd.context_driver_cmd); + ATRACE_END(); + } else if (channel_type == CONTEXT_CHANNEL_TYPE_STYLUS_STATUS) { + ATRACE_BEGIN("populate stylus context"); + ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_CONTEXT_STYLUS); + if (ret == 0) + goog_offload_populate_stylus_status_channel( + gti, frame, i, + >i->cmd.context_stylus_cmd); + ATRACE_END(); + } else if (channel_type == TOUCH_DATA_TYPE_COORD) { ATRACE_BEGIN("populate coord"); goog_offload_populate_coordinate_channel(gti, frame, i); ATRACE_END(); } else if (channel_type & TOUCH_SCAN_TYPE_MUTUAL) { ATRACE_BEGIN("populate mutual data"); cmd->type = GTI_SENSOR_DATA_TYPE_MS; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_2D(rx, tx)) { goog_offload_populate_mutual_channel(gti, frame, i, @@ -1555,17 +2027,20 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, } else if (channel_type & TOUCH_SCAN_TYPE_SELF) { ATRACE_BEGIN("populate self data"); cmd->type = GTI_SENSOR_DATA_TYPE_SS; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size == TOUCH_OFFLOAD_DATA_SIZE_1D(rx, tx)) { goog_offload_populate_self_channel(gti, frame, i, cmd->buffer, cmd->size); } ATRACE_END(); + } else { + GOOG_ERR(gti, "unrecognized channel_type %#x.\n", channel_type); } if (ret) { - GOOG_DBG("skip to populate data(type %#x, ret %d)!\n", + GOOG_DBG(gti, "skip to populate data(type %#x, ret %d)!\n", channel_type, ret); } } @@ -1575,39 +2050,83 @@ void goog_offload_populate_frame(struct goog_touch_interface *gti, void goog_update_fw_settings(struct goog_touch_interface *gti) { + int error; int ret = 0; - if (gti->offload.offload_running && gti->offload.config.filter_grip) - gti->cmd.grip_cmd.setting = GTI_GRIP_DISABLE; - else - gti->cmd.grip_cmd.setting = gti->default_grip_enabled; - ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_GRIP_MODE); - if (ret) - GOOG_WARN("unexpected return(%d)!", ret); + bool enabled = false; - if (gti->offload.offload_running && gti->offload.config.filter_palm) - gti->cmd.palm_cmd.setting = GTI_PALM_DISABLE; - else - gti->cmd.palm_cmd.setting = gti->default_palm_enabled; - ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_PALM_MODE); - if (ret) - GOOG_WARN("unexpected return(%d)!", ret); + error = goog_pm_wake_lock_nosync(gti, GTI_PM_WAKELOCK_TYPE_FW_SETTINGS, true); + if (error < 0) { + GOOG_DBG(gti, "Error while obtaining FW_SETTINGS wakelock: %d!\n", error); + return; + } + + if(!gti->ignore_grip_update) { + if (gti->offload.offload_running && gti->offload.config.filter_grip) + gti->cmd.grip_cmd.setting = GTI_GRIP_DISABLE; + else + gti->cmd.grip_cmd.setting = gti->default_grip_enabled; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_GRIP_MODE); + if (ret) + GOOG_WARN(gti, "unexpected return(%d)!", ret); + } + + if(!gti->ignore_palm_update) { + if (gti->offload.offload_running && gti->offload.config.filter_palm) + gti->cmd.palm_cmd.setting = GTI_PALM_DISABLE; + else + gti->cmd.palm_cmd.setting = gti->default_palm_enabled; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_PALM_MODE); + if (ret) + GOOG_WARN(gti, "unexpected return(%d)!", ret); + } + + if (gti->coord_filter_enabled) { + if (!gti->ignore_coord_filter_update) { + if (gti->offload.offload_running && gti->offload.config.coord_filter) + enabled = false; + else + enabled = gti->default_coord_filter_enabled; + } else { + enabled = gti->fw_coord_filter_enabled; + } + + gti->cmd.coord_filter_cmd.setting = enabled ? + GTI_COORD_FILTER_ENABLE : GTI_COORD_FILTER_DISABLE; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_COORD_FILTER_ENABLED); + if (ret) + GOOG_WARN(gti, "unexpected return(%d)!", ret); + } gti->cmd.screen_protector_mode_cmd.setting = gti->screen_protector_mode_setting; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_SCREEN_PROTECTOR_MODE); if (ret != 0) - GOOG_ERR("Failed to %s screen protector mode!\n", - gti->screen_protector_mode_setting == GTI_SCREEN_PROTECTOR_MODE_ENABLE ? - "enable" : "disable"); + GOOG_ERR(gti, "Failed to %s screen protector mode!\n", + gti->screen_protector_mode_setting == GTI_SCREEN_PROTECTOR_MODE_ENABLE ? + "enable" : "disable"); gti->cmd.heatmap_cmd.setting = GTI_HEATMAP_ENABLE; ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_HEATMAP_ENABLED); if (ret != 0) - GOOG_ERR("Failed to enable heatmap!\n"); + GOOG_ERR(gti, "Failed to enable heatmap!\n"); + + if (gti->vrr_enabled) { + gti->cmd.report_rate_cmd.setting = gti->report_rate_setting_next; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_REPORT_RATE); + if (ret != 0) + GOOG_ERR(gti, "Failed to set report rate!\n"); + } + + error = goog_pm_wake_unlock_nosync(gti, GTI_PM_WAKELOCK_TYPE_FW_SETTINGS); + if (error < 0) + GOOG_DBG(gti, "Error while releasing FW_SETTING wakelock: %d!\n", error); } static void goog_offload_set_running(struct goog_touch_interface *gti, bool running) { if (gti->offload.offload_running != running) { + GOOG_INFO(gti, "Set offload_running=%d, irq_index=%d, input_index=%d\n", + running, gti->irq_index, gti->input_index); + gti->offload.offload_running = running; goog_update_fw_settings(gti); } @@ -1620,9 +2139,17 @@ void goog_offload_input_report(void *handle, bool touch_down = 0; unsigned int tool_type = MT_TOOL_FINGER; int i; + int error; unsigned long slot_bit_active = 0; + char trace_tag[128]; + ktime_t ktime = ktime_get(); - ATRACE_BEGIN(__func__); + scnprintf(trace_tag, sizeof(trace_tag), + "%s: IDX=%lld IN_TS=%lld TS=%lld DELTA=%lld ns.\n", + __func__, report->index, + ktime_to_ns(report->timestamp), ktime_to_ns(ktime), + ktime_to_ns(ktime_sub(ktime, report->timestamp))); + ATRACE_BEGIN(trace_tag); goog_input_lock(gti); input_set_timestamp(gti->vendor_input_dev, report->timestamp); @@ -1673,20 +2200,69 @@ void goog_offload_input_report(void *handle, if (touch_down) goog_v4l2_read(gti, report->timestamp); + error = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_OFFLOAD_REPORT, true); + if (error < 0) { + GOOG_WARN(gti, "Error while obtaining OFFLOAD_REPORT wakelock: %d!\n", error); + ATRACE_END(); + return; + } goog_update_motion_filter(gti, slot_bit_active); - + error = goog_pm_wake_unlock(gti, GTI_PM_WAKELOCK_TYPE_OFFLOAD_REPORT); + if (error < 0) + GOOG_WARN(gti, "Error while releasing OFFLOAD_REPORT wakelock: %d!\n", error); ATRACE_END(); } +int gti_charger_state_change(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct goog_touch_interface *gti = + (struct goog_touch_interface *)container_of(nb, + struct goog_touch_interface, charger_notifier); + struct power_supply *psy = (struct power_supply *)data; + int ret; + + /* Attempt actual status parsing */ + if (psy && psy->desc->type == POWER_SUPPLY_TYPE_USB) { + union power_supply_propval present_val = { 0 }; + + ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, + &present_val); + if (ret < 0) + GOOG_DBG(gti, + "Error while getting power supply property: %d!\n", + ret); + else if ((u8)present_val.intval != gti->charger_state) { + /* Note: the expected values for present_val.intval are + * 0 and 1. Cast to unsigned byte to ensure the + * comparison is handled in the same variable data type. + */ + gti->context_changed.charger_state = 1; + gti->charger_state = (u8)present_val.intval; + } + } + + return 0; +} + int goog_offload_probe(struct goog_touch_interface *gti) { int ret; u16 values[2]; struct device_node *np = gti->vendor_dev->of_node; + const char *offload_dev_name = NULL; + + /* + * TODO(b/201610482): rename DEVICE_NAME in touch_offload.h for more specific. + */ + if (!of_property_read_string(np, "goog,offload-device-name", &offload_dev_name)) { + scnprintf(gti->offload.device_name, sizeof(gti->offload.device_name), + "%s_%s", DEVICE_NAME, offload_dev_name); + } if (of_property_read_u8_array(np, "goog,touch_offload_id", gti->offload_id_byte, 4)) { - GOOG_LOG("set default offload id: GOOG!\n"); + GOOG_INFO(gti, "set default offload id: GOOG!\n"); gti->offload_id_byte[0] = 'G'; gti->offload_id_byte[1] = 'O'; gti->offload_id_byte[2] = 'O'; @@ -1702,7 +2278,7 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.caps.display_width = values[0]; gti->offload.caps.display_height = values[1]; } else { - GOOG_ERR("Plesae set \"goog,display-resolution\" in dts!"); + GOOG_ERR(gti, "Please set \"goog,display-resolution\" in dts!"); } if (of_property_read_u16_array(np, "goog,channel-num", @@ -1710,7 +2286,7 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.caps.tx_size = values[0]; gti->offload.caps.rx_size = values[1]; } else { - GOOG_ERR("Plesae set \"goog,channel-num\" in dts!"); + GOOG_ERR(gti, "Please set \"goog,channel-num\" in dts!"); ret = -EINVAL; goto err_offload_probe; } @@ -1735,9 +2311,14 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.caps.touch_scan_types = TOUCH_SCAN_TYPE_MUTUAL; } - GOOG_LOG("offload.caps: data_types %#x, scan_types %#x.\n", + if (of_property_read_u16(np, "goog,offload-caps-context-channel-types", + >i->offload.caps.context_channel_types)) { + gti->offload.caps.context_channel_types = 0; + } + GOOG_INFO(gti, "offload.caps: data_types %#x, scan_types %#x, context_channel_types %#x.\n", gti->offload.caps.touch_data_types, - gti->offload.caps.touch_scan_types); + gti->offload.caps.touch_scan_types, + gti->offload.caps.context_channel_types); gti->offload.caps.continuous_reporting = true; gti->offload.caps.noise_reporting = false; @@ -1746,6 +2327,8 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.caps.size_reporting = true; gti->offload.caps.filter_grip = true; gti->offload.caps.filter_palm = true; + gti->offload.caps.coord_filter = gti->coord_filter_enabled && + of_property_read_bool(np, "goog,offload-caps-coord-filter"); gti->offload.caps.num_sensitivity_settings = 1; gti->offload.caps.rotation_reporting = of_property_read_bool(np, "goog,offload-caps-rotation-reporting"); @@ -1754,28 +2337,31 @@ int goog_offload_probe(struct goog_touch_interface *gti) gti->offload.report_cb = goog_offload_input_report; ret = touch_offload_init(>i->offload); if (ret) { - GOOG_ERR("offload init failed, ret %d!\n", ret); + GOOG_ERR(gti, "offload init failed, ret %d!\n", ret); goto err_offload_probe; } - gti->offload_enable = of_property_read_bool(np, "goog,offload-enable"); - GOOG_LOG("offload.caps: display W/H: %d * %d (Tx/Rx: %d * %d).\n", + gti->offload_enabled = of_property_read_bool(np, "goog,offload-enabled"); + GOOG_INFO(gti, "offload.caps: display W/H: %d * %d (Tx/Rx: %d * %d).\n", gti->offload.caps.display_width, gti->offload.caps.display_height, gti->offload.caps.tx_size, gti->offload.caps.rx_size); - GOOG_LOG("offload ID: \"%c%c%c%c\" / 0x%08X, offload_enable=%d.\n", + GOOG_INFO(gti, "offload ID: \"%c%c%c%c\" / 0x%08X, offload_enabled=%d.\n", gti->offload_id_byte[0], gti->offload_id_byte[1], gti->offload_id_byte[2], - gti->offload_id_byte[3], gti->offload_id, gti->offload_enable); + gti->offload_id_byte[3], gti->offload_id, gti->offload_enabled); gti->default_grip_enabled = of_property_read_bool(np, "goog,default-grip-disabled") ? GTI_GRIP_DISABLE : GTI_GRIP_ENABLE; gti->default_palm_enabled = of_property_read_bool(np, "goog,default-palm-disabled") ? GTI_PALM_DISABLE : GTI_PALM_ENABLE; + gti->default_coord_filter_enabled = of_property_read_bool(np, + "goog,default-coord-filter-disabled") ? + GTI_COORD_FILTER_DISABLE : GTI_COORD_FILTER_ENABLE; gti->heatmap_buf_size = gti->offload.caps.tx_size * gti->offload.caps.rx_size * sizeof(u16); gti->heatmap_buf = devm_kzalloc(gti->vendor_dev, gti->heatmap_buf_size, GFP_KERNEL); if (!gti->heatmap_buf) { - GOOG_ERR("heamap alloc failed!\n"); + GOOG_ERR(gti, "heamap alloc failed!\n"); ret = -ENOMEM; goto err_offload_probe; } @@ -1800,12 +2386,20 @@ int goog_offload_probe(struct goog_touch_interface *gti) ret = heatmap_probe(>i->v4l2); if (ret) { - GOOG_ERR("v4l2 init failed, ret %d!\n", ret); + GOOG_ERR(gti, "v4l2 init failed, ret %d!\n", ret); + goto err_offload_probe; + } + gti->v4l2_enabled = of_property_read_bool(np, "goog,v4l2-enabled"); + GOOG_INFO(gti, "v4l2 W/H=(%lu, %lu), v4l2_enabled=%d.\n", + gti->v4l2.width, gti->v4l2.height, gti->v4l2_enabled); + + /* Register for charger plugging status */ + gti->charger_notifier.notifier_call = gti_charger_state_change; + ret = power_supply_reg_notifier(>i->charger_notifier); + if (!ret) { + GOOG_ERR(gti, "Failed to register power_supply_reg_notifier!\n"); goto err_offload_probe; } - gti->v4l2_enable = of_property_read_bool(np, "goog,v4l2-enable"); - GOOG_LOG("v4l2 W/H=(%lu, %lu), v4l2_enable=%d.\n", - gti->v4l2.width, gti->v4l2.height, gti->v4l2_enable); err_offload_probe: return ret; @@ -1818,29 +2412,37 @@ void goog_offload_remove(struct goog_touch_interface *gti) bool goog_input_legacy_report(struct goog_touch_interface *gti) { - if (!gti->offload.offload_running || gti->force_legacy_report) + if (!gti->offload.offload_running) return true; return false; } -int goog_input_process(struct goog_touch_interface *gti) +int goog_input_process(struct goog_touch_interface *gti, bool reset_data) { int ret = 0; struct touch_offload_frame **frame = >i->offload_frame; /* * Only do the input process if active slot(s) update - * or slot(s) state change. + * or slot(s) state change or resetting frame data. */ if (!(gti->slot_bit_active & gti->slot_bit_in_use) && - !gti->slot_bit_changed) + !gti->slot_bit_changed && !reset_data) return -EPERM; - if (gti->offload_enable) { + /* + * Increase the input index when any slot bit changed which + * means the finger is down or up. + */ + if (gti->slot_bit_changed) + gti->input_index++; + + if (gti->offload_enabled) { ret = touch_offload_reserve_frame(>i->offload, frame); if (ret != 0 || frame == NULL) { - GOOG_ERR("could not reserve a frame(ret %d)!\n", ret); + GOOG_DBG(gti, "could not reserve a frame(ret %d)!\n", ret); + /* Stop offload when there are no buffers available. */ goog_offload_set_running(gti, false); /* @@ -1851,10 +2453,10 @@ int goog_input_process(struct goog_touch_interface *gti) ret = -EBUSY; } else { goog_offload_set_running(gti, true); - goog_offload_populate_frame(gti, *frame); + goog_offload_populate_frame(gti, *frame, reset_data); ret = touch_offload_queue_frame(>i->offload, *frame); if (ret) - GOOG_ERR("failed to queue reserved frame(ret %d)!\n", ret); + GOOG_ERR(gti, "failed to queue reserved frame(ret %d)!\n", ret); else gti->offload_frame = NULL; } @@ -1865,7 +2467,7 @@ int goog_input_process(struct goog_touch_interface *gti) * Otherwise, heatmap will be handled for both offload and v4l2 * during goog_offload_populate_frame(). */ - if (!gti->offload.offload_running && gti->v4l2_enable) { + if (!gti->offload.offload_running && gti->v4l2_enabled) { int ret; struct gti_sensor_data_cmd *cmd = >i->cmd.sensor_data_cmd; @@ -1873,7 +2475,7 @@ int goog_input_process(struct goog_touch_interface *gti) cmd->buffer = NULL; cmd->size = 0; cmd->type = GTI_SENSOR_DATA_TYPE_MS; - ret = goog_process_vendor_cmd(gti, GTI_CMD_GET_SENSOR_DATA); + ret = goog_get_sensor_data(gti, cmd, reset_data); if (ret == 0 && cmd->buffer && cmd->size) memcpy(gti->heatmap_buf, cmd->buffer, cmd->size); goog_v4l2_read(gti, gti->input_timestamp); @@ -1904,18 +2506,6 @@ void goog_input_set_timestamp( struct goog_touch_interface *gti, struct input_dev *dev, ktime_t timestamp) { - /* Specific case to handle all fingers release. */ - if (!ktime_compare(timestamp, KTIME_RELEASE_ALL)) { - GOOG_DBG("Enable force_legacy_report for all fingers release.\n"); - timestamp = ktime_get(); - gti->force_legacy_report = true; - } else { - if (gti->force_legacy_report) { - GOOG_DBG("Disable force_legacy_report as usual state.\n"); - gti->force_legacy_report = false; - } - } - if (goog_input_legacy_report(gti)) input_set_timestamp(dev, timestamp); @@ -1929,7 +2519,7 @@ void goog_input_mt_slot( struct input_dev *dev, int slot) { if (slot < 0 || slot >= MAX_SLOTS) { - GOOG_ERR("Invalid slot: %d\n", slot); + GOOG_ERR(gti, "Invalid slot: %d\n", slot); return; } @@ -1942,7 +2532,7 @@ void goog_input_mt_slot( * This is for input report switch between offload and legacy. */ if (!gti->slot_bit_in_use && !gti->input_timestamp_changed) - GOOG_ERR("please exec goog_input_set_timestamp before %s!\n", __func__); + GOOG_ERR(gti, "please exec goog_input_set_timestamp before %s!\n", __func__); set_bit(slot, >i->slot_bit_in_use); } EXPORT_SYMBOL(goog_input_mt_slot); @@ -1954,7 +2544,8 @@ void goog_input_mt_report_slot_state( if (goog_input_legacy_report(gti)) input_mt_report_slot_state(dev, tool_type, active); - if (tool_type == MT_TOOL_FINGER) { + switch (tool_type) { + case MT_TOOL_FINGER: if (active) { gti->offload.coords[gti->slot].status = COORD_STATUS_FINGER; if (!test_and_set_bit(gti->slot, @@ -1968,7 +2559,16 @@ void goog_input_mt_report_slot_state( set_bit(gti->slot, >i->slot_bit_changed); } } + break; + + default: + if (!goog_input_legacy_report(gti)) { + GOOG_WARN(gti, "unexcepted input tool_type(%#x) active(%d)!\n", + tool_type, active); + } + break; } + } EXPORT_SYMBOL(goog_input_mt_report_slot_state); @@ -2020,21 +2620,59 @@ void goog_input_sync(struct goog_touch_interface *gti, struct input_dev *dev) } EXPORT_SYMBOL(goog_input_sync); +void goog_input_release_all_fingers(struct goog_touch_interface *gti) +{ + int i; + + goog_input_lock(gti); + + goog_input_set_timestamp(gti, gti->vendor_input_dev, ktime_get()); + for (i = 0; i < MAX_SLOTS; i++) { + goog_input_mt_slot(gti, gti->vendor_input_dev, i); + goog_input_mt_report_slot_state( + gti, gti->vendor_input_dev, MT_TOOL_FINGER, false); + } + goog_input_report_key(gti, gti->vendor_input_dev, BTN_TOUCH, 0); + goog_input_sync(gti, gti->vendor_input_dev); + + goog_input_unlock(gti); + + goog_input_process(gti, true); +} + void goog_register_tbn(struct goog_touch_interface *gti) { struct device_node *np = gti->vendor_dev->of_node; - gti->tbn_enable = of_property_read_bool(np, "goog,tbn-enable"); - if (gti->tbn_enable) { + gti->tbn_enabled = of_property_read_bool(np, "goog,tbn-enabled"); + if (gti->tbn_enabled) { if (register_tbn(>i->tbn_register_mask)) { - GOOG_ERR("failed to register tbn context!\n"); - gti->tbn_enable = false; + GOOG_ERR(gti, "failed to register tbn context!\n"); + gti->tbn_enabled = false; } else { - GOOG_LOG("tbn_register_mask = %#x.\n", gti->tbn_register_mask); + GOOG_INFO(gti, "tbn_register_mask = %#x.\n", gti->tbn_register_mask); } } } +static int goog_get_context_driver_nop( + void *private_data, struct gti_context_driver_cmd *cmd) +{ + return -ESRCH; +} + +static int goog_get_context_stylus_nop( + void *private_data, struct gti_context_stylus_cmd *cmd) +{ + return -ESRCH; +} + +static int goog_get_coord_filter_enabled_nop( + void *private_data, struct gti_coord_filter_cmd *cmd) +{ + return -ESRCH; +} + static int goog_get_fw_version_nop( void *private_data, struct gti_fw_version_cmd *cmd) { @@ -2125,6 +2763,12 @@ static int goog_set_continuous_report_nop( return -ESRCH; } +static int goog_set_coord_filter_enabled_nop( + void *private_data, struct gti_coord_filter_cmd *cmd) +{ + return -ESRCH; +} + static int goog_set_grip_mode_nop( void *private_data, struct gti_grip_cmd *cmd) { @@ -2149,6 +2793,12 @@ static int goog_set_palm_mode_nop( return -ESRCH; } +static int goog_set_report_rate_nop( + void *private_data, struct gti_report_rate_cmd *cmd) +{ + return -ESRCH; +} + static int goog_set_scan_mode_nop( void *private_data, struct gti_scan_cmd *cmd) { @@ -2167,10 +2817,81 @@ static int goog_set_sensing_mode_nop( return -ESRCH; } +void goog_init_input(struct goog_touch_interface *gti) +{ + int i; + + if (!gti) + return; + + INIT_KFIFO(gti->debug_fifo_hc); + INIT_KFIFO(gti->debug_fifo_input); + for (i = 0 ; i < MAX_SLOTS ; i++) + gti->debug_input[i].slot = i; + + if (gti->vendor_dev && gti->vendor_input_dev) { + /* + * Initialize the ABS_MT_ORIENTATION to support orientation reporting. + * Initialize the ABS_MT_TOUCH_MAJOR and ABS_MT_TOUCH_MINOR depending on + * the larger values of ABS_MT_POSITION_X and ABS_MT_POSITION_Y to support + * shape algo reporting. + */ + if (gti->offload.caps.rotation_reporting) { + int abs_x_max = input_abs_get_max(gti->vendor_input_dev, ABS_MT_POSITION_X); + int abs_x_min = input_abs_get_min(gti->vendor_input_dev, ABS_MT_POSITION_X); + int abs_x_res = input_abs_get_res(gti->vendor_input_dev, ABS_MT_POSITION_X); + int abs_y_max = input_abs_get_max(gti->vendor_input_dev, ABS_MT_POSITION_Y); + int abs_y_min = input_abs_get_min(gti->vendor_input_dev, ABS_MT_POSITION_Y); + int abs_y_res = input_abs_get_res(gti->vendor_input_dev, ABS_MT_POSITION_Y); + int abs_major_max = abs_x_max; + int abs_major_min = abs_x_min; + int abs_major_res = abs_x_res; + int abs_minor_max = abs_y_max; + int abs_minor_min = abs_y_min; + int abs_minor_res = abs_y_res; + + if (abs_x_max < abs_y_max) { + swap(abs_major_max, abs_minor_max); + swap(abs_major_min, abs_minor_min); + swap(abs_major_res, abs_minor_res); + } + input_set_abs_params(gti->vendor_input_dev, ABS_MT_ORIENTATION, + -4096, 4096, 0, 0); + input_set_abs_params(gti->vendor_input_dev, ABS_MT_TOUCH_MAJOR, + abs_major_min, abs_major_max, 0, 0); + input_set_abs_params(gti->vendor_input_dev, ABS_MT_TOUCH_MINOR, + abs_minor_min, abs_minor_max, 0, 0); + input_abs_set_res(gti->vendor_input_dev, ABS_MT_TOUCH_MAJOR, abs_major_res); + input_abs_set_res(gti->vendor_input_dev, ABS_MT_TOUCH_MINOR, abs_minor_res); + } + + /* + * Initialize the ABS_MT_TOOL_TYPE to support touch cancel. + */ + input_set_abs_params(gti->vendor_input_dev, ABS_MT_TOOL_TYPE, + MT_TOOL_FINGER, MT_TOOL_PALM, 0, 0); + } +} + void goog_init_options(struct goog_touch_interface *gti, struct gti_optional_configuration *options) { + /* Initialize the common features. */ + gti->mf_mode = GTI_MF_MODE_DEFAULT; + gti->screen_protector_mode_setting = GTI_SCREEN_PROTECTOR_MODE_DISABLE; + gti->display_state = GTI_DISPLAY_STATE_ON; + + if (gti->vendor_dev) { + struct device_node *np = gti->vendor_dev->of_node; + + gti->ignore_force_active = of_property_read_bool(np, "goog,ignore-force-active"); + gti->coord_filter_enabled = of_property_read_bool(np, "goog,coord-filter-enabled"); + } + /* Initialize default functions. */ + gti->options.get_context_driver = goog_get_context_driver_nop; + gti->options.get_context_stylus = goog_get_context_stylus_nop; + gti->options.get_coord_filter_enabled = goog_get_coord_filter_enabled_nop; gti->options.get_fw_version = goog_get_fw_version_nop; gti->options.get_grip_mode = goog_get_grip_mode_nop; gti->options.get_irq_mode = goog_get_irq_mode_nop; @@ -2186,16 +2907,24 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.reset = goog_reset_nop; gti->options.selftest = goog_selftest_nop; gti->options.set_continuous_report = goog_set_continuous_report_nop; + gti->options.set_coord_filter_enabled = goog_set_coord_filter_enabled_nop; gti->options.set_grip_mode = goog_set_grip_mode_nop; gti->options.set_heatmap_enabled = goog_set_heatmap_enabled_nop; gti->options.set_irq_mode = goog_set_irq_mode_nop; gti->options.set_palm_mode = goog_set_palm_mode_nop; + gti->options.set_report_rate = goog_set_report_rate_nop; gti->options.set_scan_mode = goog_set_scan_mode_nop; gti->options.set_screen_protector_mode = goog_set_screen_protector_mode_nop; gti->options.set_sensing_mode = goog_set_sensing_mode_nop; /* Set optional operation if available. */ if (options) { + if (options->get_context_driver) + gti->options.get_context_driver = options->get_context_driver; + if (options->get_context_stylus) + gti->options.get_context_stylus = options->get_context_stylus; + if (options->get_coord_filter_enabled) + gti->options.get_coord_filter_enabled = options->get_coord_filter_enabled; if (options->get_fw_version) gti->options.get_fw_version = options->get_fw_version; if (options->get_grip_mode) @@ -2228,6 +2957,8 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.selftest = options->selftest; if (options->set_continuous_report) gti->options.set_continuous_report = options->set_continuous_report; + if (options->set_coord_filter_enabled) + gti->options.set_coord_filter_enabled = options->set_coord_filter_enabled; if (options->set_grip_mode) gti->options.set_grip_mode = options->set_grip_mode; if (options->set_heatmap_enabled) @@ -2236,6 +2967,8 @@ void goog_init_options(struct goog_touch_interface *gti, gti->options.set_irq_mode = options->set_irq_mode; if (options->set_palm_mode) gti->options.set_palm_mode = options->set_palm_mode; + if (options->set_report_rate) + gti->options.set_report_rate = options->set_report_rate; if (options->set_scan_mode) gti->options.set_scan_mode = options->set_scan_mode; if (options->set_screen_protector_mode) @@ -2245,21 +2978,19 @@ void goog_init_options(struct goog_touch_interface *gti, } } -int goog_pm_wake_lock(struct goog_touch_interface *gti, +int goog_pm_wake_lock_nosync(struct goog_touch_interface *gti, enum gti_pm_wakelock_type type, bool skip_pm_resume) { struct gti_pm* pm = NULL; - int ret = 0; - bool wait_resume = false; - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; pm = >i->pm; mutex_lock(&pm->lock_mutex); if (pm->locks & type) { - GOOG_DBG("unexpectedly lock: locks=0x%04X, type=0x%04X\n", + GOOG_DBG(gti, "unexpectedly lock: locks=0x%04X, type=0x%04X\n", pm->locks, type); mutex_unlock(&pm->lock_mutex); return -EINVAL; @@ -2279,50 +3010,48 @@ int goog_pm_wake_lock(struct goog_touch_interface *gti, if (skip_pm_resume) { mutex_unlock(&pm->lock_mutex); - return ret; + return 0; } - /* - * When triggering a wake, wait up to one second to resume. - * SCREEN_ON does not need to wait. - */ - if (type != GTI_PM_WAKELOCK_TYPE_SCREEN_ON) - wait_resume = true; - + pm->new_state = GTI_PM_RESUME; + pm->update_state = true; + queue_work(pm->event_wq, &pm->state_update_work); mutex_unlock(&pm->lock_mutex); + return 0; +} +EXPORT_SYMBOL(goog_pm_wake_lock_nosync); - /* Complete or cancel any outstanding transitions */ - cancel_work_sync(&pm->suspend_work); - cancel_work_sync(&pm->resume_work); - - queue_work(pm->event_wq, &pm->resume_work); +int goog_pm_wake_lock(struct goog_touch_interface *gti, + enum gti_pm_wakelock_type type, bool skip_pm_resume) +{ + struct gti_pm* pm = NULL; + int ret = 0; - if (wait_resume) { - wait_for_completion_timeout(&pm->bus_resumed, msecs_to_jiffies(MSEC_PER_SEC)); - if (pm->state != GTI_PM_RESUME) { - GOOG_ERR("Failed to wake the touch bus.\n"); - ret = -ETIMEDOUT; - } - } + if ((gti == NULL) || !gti->pm.enabled) + return -ENODEV; + pm = >i->pm; + ret = goog_pm_wake_lock_nosync(gti, type, skip_pm_resume); + if (ret < 0) return ret; + flush_workqueue(pm->event_wq); return ret; } EXPORT_SYMBOL(goog_pm_wake_lock); -int goog_pm_wake_unlock(struct goog_touch_interface *gti, +int goog_pm_wake_unlock_nosync(struct goog_touch_interface *gti, enum gti_pm_wakelock_type type) { struct gti_pm* pm = NULL; int ret = 0; - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; pm = >i->pm; mutex_lock(&pm->lock_mutex); if (!(pm->locks & type)) { - GOOG_DBG("unexpectedly unlock: locks=0x%04X, type=0x%04X\n", + GOOG_DBG(gti, "unexpectedly unlock: locks=0x%04X, type=0x%04X\n", pm->locks, type); mutex_unlock(&pm->lock_mutex); return -EINVAL; @@ -2331,25 +3060,37 @@ int goog_pm_wake_unlock(struct goog_touch_interface *gti, pm->locks &= ~type; if (pm->locks == 0) { - mutex_unlock(&pm->lock_mutex); - /* Complete or cancel any outstanding transitions */ - cancel_work_sync(&pm->suspend_work); - cancel_work_sync(&pm->resume_work); - - mutex_lock(&pm->lock_mutex); - if (pm->locks == 0) - queue_work(pm->event_wq, &pm->suspend_work); + pm->new_state = GTI_PM_SUSPEND; + pm->update_state = true; + queue_work(pm->event_wq, &pm->state_update_work); } mutex_unlock(&pm->lock_mutex); return ret; } +EXPORT_SYMBOL(goog_pm_wake_unlock_nosync); + +int goog_pm_wake_unlock(struct goog_touch_interface *gti, + enum gti_pm_wakelock_type type) +{ + struct gti_pm* pm = NULL; + int ret = 0; + + if ((gti == NULL) || !gti->pm.enabled) + return -ENODEV; + pm = >i->pm; + + ret = goog_pm_wake_unlock_nosync(gti, type); + if (ret < 0) return ret; + flush_workqueue(pm->event_wq); + return ret; +} EXPORT_SYMBOL(goog_pm_wake_unlock); bool goog_pm_wake_check_locked(struct goog_touch_interface *gti, enum gti_pm_wakelock_type type) { - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; return gti->pm.locks & type ? true : false; @@ -2358,73 +3099,95 @@ EXPORT_SYMBOL(goog_pm_wake_check_locked); u32 goog_pm_wake_get_locks(struct goog_touch_interface *gti) { - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; return gti->pm.locks; } EXPORT_SYMBOL(goog_pm_wake_get_locks); -static void goog_pm_suspend_work(struct work_struct *work) +static void goog_pm_suspend(struct gti_pm *pm) { - struct gti_pm *pm = container_of(work, struct gti_pm, suspend_work); struct goog_touch_interface *gti = container_of(pm, struct goog_touch_interface, pm); int ret = 0; /* exit directly if device is already in suspend state */ if (pm->state == GTI_PM_SUSPEND) { - GOOG_WARN("GTI already suspended!\n"); + GOOG_WARN(gti, "GTI already suspended!\n"); return; } + + GOOG_INFO(gti, "irq_index: %llu, input_index: %llu.\n", gti->irq_index, gti->input_index); pm->state = GTI_PM_SUSPEND; - reinit_completion(&pm->bus_resumed); if (pm->suspend) pm->suspend(gti->vendor_dev); if (gti->tbn_register_mask) { ret = tbn_release_bus(gti->tbn_register_mask); if (ret) - GOOG_ERR("tbn_release_bus failed, ret %d!\n", ret); + GOOG_ERR(gti, "tbn_release_bus failed, ret %d!\n", ret); } + gti_debug_hc_dump(gti); gti_debug_input_dump(gti); + goog_input_release_all_fingers(gti); + pm_relax(gti->dev); } -static void goog_pm_resume_work(struct work_struct *work) +static void goog_pm_resume(struct gti_pm *pm) { - struct gti_pm *pm = container_of(work, struct gti_pm, resume_work); struct goog_touch_interface *gti = container_of(pm, struct goog_touch_interface, pm); int ret = 0; /* exit directly if device isn't in suspend state */ if (pm->state == GTI_PM_RESUME) { - GOOG_WARN("GTI already resumed!\n"); + GOOG_WARN(gti, "GTI already resumed!\n"); return; } - pm->state = GTI_PM_RESUME; pm_stay_awake(gti->dev); if (gti->tbn_register_mask) { - ret = tbn_request_bus(gti->tbn_register_mask); + gti->lptw_triggered = false; + ret = tbn_request_bus_with_result(gti->tbn_register_mask, >i->lptw_triggered); if (ret) - GOOG_ERR("tbn_request_bus failed, ret %d!\n", ret); + GOOG_ERR(gti, "tbn_request_bus failed, ret %d!\n", ret); } if (pm->resume) pm->resume(gti->vendor_dev); - complete_all(&pm->bus_resumed); + pm->state = GTI_PM_RESUME; +} + +void goog_pm_state_update_work(struct work_struct *work) { + struct gti_pm *pm = container_of(work, struct gti_pm, state_update_work); + enum gti_pm_state new_state; + + mutex_lock(&pm->lock_mutex); + while (pm->update_state) { + pm->update_state = false; + new_state = pm->new_state; + mutex_unlock(&pm->lock_mutex); + if (new_state != pm->state) { + if (new_state == GTI_PM_RESUME) + goog_pm_resume(pm); + else + goog_pm_suspend(pm); + } + mutex_lock(&pm->lock_mutex); + } + mutex_unlock(&pm->lock_mutex); } int goog_pm_register_notification(struct goog_touch_interface *gti, const struct dev_pm_ops* ops) { - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; gti->pm.resume = ops->resume; @@ -2435,7 +3198,7 @@ EXPORT_SYMBOL(goog_pm_register_notification); int goog_pm_unregister_notification(struct goog_touch_interface *gti) { - if (gti == NULL) + if ((gti == NULL) || !gti->pm.enabled) return -ENODEV; gti->pm.resume = NULL; @@ -2448,31 +3211,45 @@ void goog_notify_fw_status_changed(struct goog_touch_interface *gti, enum gti_fw_status status, struct gti_fw_status_data* data) { switch (status) { - case GTI_FW_STATUE_RESET: - GOOG_LOG("Firmware has been reset\n"); + case GTI_FW_STATUS_RESET: + GOOG_INFO(gti, "Firmware has been reset\n"); + goog_input_release_all_fingers(gti); goog_update_fw_settings(gti); break; - case GTI_FW_STATUE_PALM_ENTER: - GOOG_LOG("Enter palm mode\n"); + case GTI_FW_STATUS_PALM_ENTER: + GOOG_INFO(gti, "Enter palm mode\n"); + break; + case GTI_FW_STATUS_PALM_EXIT: + GOOG_INFO(gti, "Exit palm mode\n"); break; - case GTI_FW_STATUE_PALM_EXIT: - GOOG_LOG("Exit palm mode\n"); + case GTI_FW_STATUS_GRIP_ENTER: + GOOG_INFO(gti, "Enter grip mode\n"); break; - case GTI_FW_STATUE_GRIP_ENTER: - GOOG_LOG("Enter grip mode\n"); + case GTI_FW_STATUS_GRIP_EXIT: + GOOG_INFO(gti, "Exit grip mode\n"); break; - case GTI_FW_STATUE_GRIP_EXIT: - GOOG_LOG("Exit grip mode\n"); + case GTI_FW_STATUS_WATER_ENTER: + GOOG_INFO(gti, "Enter water mode\n"); + gti->fw_status.water_mode = 1; + gti->context_changed.water_mode = 1; break; - case GTI_FW_STATUE_NOISE_MODE: + case GTI_FW_STATUS_WATER_EXIT: + GOOG_INFO(gti, "Exit water mode\n"); + gti->fw_status.water_mode = 0; + gti->context_changed.water_mode = 1; + break; + case GTI_FW_STATUS_NOISE_MODE: if (data == NULL) { - GOOG_LOG("Noise level is changed, level: unknown\n"); + GOOG_INFO(gti, "Noise level is changed, level: unknown\n"); } else { if (data->noise_level == GTI_NOISE_MODE_EXIT) { - GOOG_LOG("Exit noise mode\n"); + GOOG_INFO(gti, "Exit noise mode\n"); + gti->fw_status.noise_level= 0; } else { - GOOG_LOG("Enter noise mode, level: %d\n", data->noise_level); + GOOG_INFO(gti, "Enter noise mode, level: %d\n", data->noise_level); + gti->fw_status.noise_level = data->noise_level; } + gti->context_changed.noise_state = 1; } break; default: @@ -2491,19 +3268,17 @@ static int goog_pm_probe(struct goog_touch_interface *gti) pm->event_wq = alloc_workqueue( "gti_pm_wq", WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); if (!pm->event_wq) { - GOOG_ERR("Failed to create work thread for pm!\n"); + GOOG_ERR(gti, "Failed to create work thread for pm!\n"); ret = -ENOMEM; goto err_alloc_workqueue; } mutex_init(&pm->lock_mutex); - INIT_WORK(&pm->suspend_work, goog_pm_suspend_work); - INIT_WORK(&pm->resume_work, goog_pm_resume_work); - - init_completion(&pm->bus_resumed); - complete_all(&pm->bus_resumed); + INIT_WORK(&pm->state_update_work, goog_pm_state_update_work); - return ret; + /* init pm_qos. */ + cpu_latency_qos_add_request(>i->pm_qos_req, PM_QOS_DEFAULT_VALUE); + pm->enabled = true; err_alloc_workqueue: return ret; @@ -2512,10 +3287,277 @@ err_alloc_workqueue: static int goog_pm_remove(struct goog_touch_interface *gti) { struct gti_pm* pm = >i->pm; - if (pm->event_wq) - destroy_workqueue(pm->event_wq); + + if (pm->enabled) { + pm->enabled = false; + cpu_latency_qos_remove_request(>i->pm_qos_req); + if (pm->event_wq) + destroy_workqueue(pm->event_wq); + } + + return 0; +} + +static void goog_lookup_touch_report_rate(struct goog_touch_interface *gti) +{ + int i; + u32 next_report_rate = 0; + + for (i = 0; i < gti->report_rate_table_size; i++) { + if (gti->display_vrefresh <= gti->display_refresh_rate_table[i]) { + next_report_rate = gti->touch_report_rate_table[i]; + break; + } + } + + /* + * Set the touch report as minimum value if the display_vrefresh is smaller + * than the minimum value of goog,display-vrr-table. + */ + if (next_report_rate == 0) + next_report_rate = gti->touch_report_rate_table[0]; + + if (gti->report_rate_setting_next != next_report_rate) { + cancel_delayed_work_sync(>i->set_report_rate_work); + gti->report_rate_setting_next = next_report_rate; + } + + if (gti->report_rate_setting_next != gti->report_rate_setting && + gti->pm.state == GTI_PM_RESUME) { + queue_delayed_work(gti->pm.event_wq, >i->set_report_rate_work, + (gti->report_rate_setting_next > gti->report_rate_setting) ? + msecs_to_jiffies(gti->increase_report_rate_delay * MSEC_PER_SEC) : + msecs_to_jiffies(gti->decrease_report_rate_delay * MSEC_PER_SEC)); + } +} + +static void goog_set_report_rate_work(struct work_struct *work) +{ + int ret; + struct goog_touch_interface *gti; + struct delayed_work *delayed_work; + delayed_work = container_of(work, struct delayed_work, work); + gti = container_of(delayed_work, struct goog_touch_interface, set_report_rate_work); + + if (gti->pm.state == GTI_PM_SUSPEND) + return; + + if (gti->report_rate_setting == gti->report_rate_setting_next) + return; + + /* Retry it 10ms later if there is finger on the screen. */ + if (gti->slot_bit_active) { + queue_delayed_work(gti->pm.event_wq, >i->set_report_rate_work, + msecs_to_jiffies(10)); + return; + } + + gti->cmd.report_rate_cmd.setting = gti->report_rate_setting_next; + ret = goog_process_vendor_cmd(gti, GTI_CMD_SET_REPORT_RATE); + if (ret != 0) { + GOOG_ERR(gti, "Failed to set report rate!\n"); + return; + } + + gti->report_rate_setting = gti->report_rate_setting_next; + gti->context_changed.touch_report_rate = 1; +} + +static int goog_init_variable_report_rate(struct goog_touch_interface *gti) +{ + int table_size = 0; + + if (!gti->pm.event_wq) { + GOOG_ERR(gti, "No workqueue for variable report rate.\n"); + return -ENODEV; + } + + gti->vrr_enabled = of_property_read_bool(gti->vendor_dev->of_node, + "goog,vrr-enabled"); + if (!gti->vrr_enabled) + return 0; + + table_size = of_property_count_u32_elems(gti->vendor_dev->of_node, + "goog,vrr-display-rate"); + if (table_size != of_property_count_u32_elems(gti->vendor_dev->of_node, + "goog,vrr-touch-rate")) { + GOOG_ERR(gti, "Table size mismatch!\n"); + goto init_variable_report_rate_failed; + } + + gti->report_rate_table_size = table_size; + + gti->display_refresh_rate_table = devm_kzalloc(gti->vendor_dev, + sizeof(u32) * table_size, GFP_KERNEL); + if (!gti->display_refresh_rate_table) { + GOOG_ERR(gti, "display_refresh_rate_table alloc failed.\n"); + goto init_variable_report_rate_failed; + } + + gti->touch_report_rate_table = devm_kzalloc(gti->vendor_dev, + sizeof(u32) * table_size, GFP_KERNEL); + if (!gti->touch_report_rate_table) { + GOOG_ERR(gti, "touch_report_rate_table alloc failed.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32_array(gti->vendor_dev->of_node, "goog,vrr-display-rate", + gti->display_refresh_rate_table, table_size)) { + GOOG_ERR(gti, "Failed to parse goog,display-vrr-table.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32_array(gti->vendor_dev->of_node, "goog,vrr-touch-rate", + gti->touch_report_rate_table, table_size)) { + GOOG_ERR(gti, "Failed to parse goog,touch-vrr-table.\n"); + goto init_variable_report_rate_failed; + } + + if (of_property_read_u32(gti->vendor_dev->of_node, "goog,vrr-up-delay", + >i->increase_report_rate_delay)) { + gti->increase_report_rate_delay = 0; + } + + if (of_property_read_u32(gti->vendor_dev->of_node, "goog,vrr-down-delay", + >i->decrease_report_rate_delay)) { + gti->decrease_report_rate_delay = 0; + } + + GOOG_INFO(gti, "Default report rate: %uHz, report rate delay %u/%u)", + gti->touch_report_rate_table[0], + gti->increase_report_rate_delay, + gti->decrease_report_rate_delay); + + gti->report_rate_setting = gti->touch_report_rate_table[0]; + gti->report_rate_setting_next = gti->touch_report_rate_table[0]; + INIT_DELAYED_WORK(>i->set_report_rate_work, goog_set_report_rate_work); + return 0; + +init_variable_report_rate_failed: + gti->vrr_enabled = false; + devm_kfree(gti->vendor_dev, gti->display_refresh_rate_table); + devm_kfree(gti->vendor_dev, gti->touch_report_rate_table); + + return 0; +} + +int goog_get_lptw_triggered(struct goog_touch_interface *gti) +{ + if (gti == NULL) + return -ENODEV; + + return gti->lptw_triggered; +} +EXPORT_SYMBOL(goog_get_lptw_triggered); + +static irqreturn_t gti_irq_handler(int irq, void *data) +{ + irqreturn_t ret; + struct goog_touch_interface *gti = (struct goog_touch_interface *)data; + + gti->irq_index++; + if (gti->vendor_irq_handler) + ret = gti->vendor_irq_handler(irq, gti->vendor_irq_cookie); + else + ret = IRQ_WAKE_THREAD; + gti_debug_hc_update(gti, true); + return ret; +} + +static irqreturn_t gti_irq_thread_fn(int irq, void *data) +{ + int error; + irqreturn_t ret = IRQ_NONE; + struct goog_touch_interface *gti = (struct goog_touch_interface *)data; + + ATRACE_BEGIN(__func__); + + if (gti->tbn_enabled) { + error = goog_pm_wake_lock(gti, GTI_PM_WAKELOCK_TYPE_IRQ, true); + if (error < 0) { + GOOG_WARN(gti, "Skipping stray interrupt, pm state: (%d, %d)\n", + gti->pm.state, gti->pm.new_state); + ATRACE_END(); + return IRQ_HANDLED; + } + } + + cpu_latency_qos_update_request(>i->pm_qos_req, 100 /* usec */); + + /* + * Some vendor drivers read sensor data inside vendor_irq_thread_fn. + * We need to lock input_process_lock before vendor_irq_thread_fn to + * avoid thread safe issue. + */ + mutex_lock(>i->input_process_lock); + + if (gti->vendor_irq_thread_fn) + ret = gti->vendor_irq_thread_fn(irq, gti->vendor_irq_cookie); + else + ret = IRQ_HANDLED; + + goog_input_process(gti, false); + + mutex_unlock(>i->input_process_lock); + + gti_debug_hc_update(gti, false); + cpu_latency_qos_update_request(>i->pm_qos_req, PM_QOS_DEFAULT_VALUE); + if (gti->tbn_enabled) + goog_pm_wake_unlock_nosync(gti, GTI_PM_WAKELOCK_TYPE_IRQ); + ATRACE_END(); + + return ret; +} + +int goog_devm_request_threaded_irq(struct goog_touch_interface *gti, + struct device *dev, unsigned int irq, + irq_handler_t handler, irq_handler_t thread_fn, + unsigned long irqflags, const char *devname, + void *dev_id) +{ + int ret; + + if (gti) { + ret = devm_request_threaded_irq(dev, irq, gti_irq_handler, gti_irq_thread_fn, + irqflags, devname, gti); + if (dev_id) + gti->vendor_irq_cookie = dev_id; + if (handler) + gti->vendor_irq_handler = handler; + if (thread_fn) + gti->vendor_irq_thread_fn = thread_fn; + } else { + ret = devm_request_threaded_irq(dev, irq, handler, thread_fn, + irqflags, devname, dev_id); + } + + return ret; } +EXPORT_SYMBOL(goog_devm_request_threaded_irq); + +int goog_request_threaded_irq(struct goog_touch_interface *gti, + unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, + unsigned long irqflags, const char *devname, void *dev_id) +{ + int ret; + + if (gti) { + ret = request_threaded_irq(irq, gti_irq_handler, gti_irq_thread_fn, + irqflags, devname, gti); + if (dev_id) + gti->vendor_irq_cookie = dev_id; + if (handler) + gti->vendor_irq_handler = handler; + if (thread_fn) + gti->vendor_irq_thread_fn = thread_fn; + } else { + ret = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, dev_id); + } + + return ret; +} +EXPORT_SYMBOL(goog_request_threaded_irq); struct goog_touch_interface *goog_touch_interface_probe( void *private_data, @@ -2529,41 +3571,33 @@ struct goog_touch_interface *goog_touch_interface_probe( struct goog_touch_interface *gti; if (!dev || !input_dev || !default_handler) { - GOOG_ERR("invalid dev/input_dev or default_handler!\n"); + pr_err("%s: error: invalid dev/input_dev or default_handler!\n", __func__); return NULL; } gti = devm_kzalloc(dev, sizeof(struct goog_touch_interface), GFP_KERNEL); if (gti) { - int i; - gti->vendor_private_data = private_data; gti->vendor_dev = dev; gti->vendor_input_dev = input_dev; gti->vendor_default_handler = default_handler; - gti->mf_mode = GTI_MF_MODE_DEFAULT; - gti->screen_protector_mode_setting = GTI_SCREEN_PROTECTOR_MODE_DISABLE; mutex_init(>i->input_lock); - goog_offload_probe(gti); - register_panel_bridge(gti); - goog_register_tbn(gti); - goog_init_options(gti, options); - goog_update_fw_settings(gti); - INIT_KFIFO(gti->debug_fifo); - for (i = 0 ; i < MAX_SLOTS ; i++) - gti->debug_input[i].slot = i; - /* - * Initialize the ABS_MT_TOOL_TYPE to support touch cancel. - */ - input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, - MT_TOOL_FINGER, MT_TOOL_PALM, 0, 0); + mutex_init(>i->input_process_lock); } if (!gti_class) - gti_class = class_create(THIS_MODULE, "goog_touch_interface"); + gti_class = class_create(THIS_MODULE, GTI_NAME); if (gti && gti_class) { - char *name = kasprintf(GFP_KERNEL, "gti.%d", gti_dev_num); + u32 dev_id = gti_dev_num; + char *name; + + if (gti->vendor_dev) { + struct device_node *np = gti->vendor_dev->of_node; + + of_property_read_u32(np, "goog,dev-id", &dev_id); + } + name = kasprintf(GFP_KERNEL, "gti.%d", dev_id); if (name && !alloc_chrdev_region(>i->dev_id, 0, 1, name)) { @@ -2571,19 +3605,22 @@ struct goog_touch_interface *goog_touch_interface_probe( gti->dev_id, gti, name); if (gti->dev) { gti_dev_num++; - GOOG_LOG("device create \"%s\".\n", name); + GOOG_INFO(gti, "device create \"%s\".\n", name); if (gti->vendor_dev) { ret = sysfs_create_link(>i->dev->kobj, >i->vendor_dev->kobj, "vendor"); - if (ret) - GOOG_ERR("sysfs_create_link() failed for vendor, ret=%d!\n", ret); + if (ret) { + GOOG_ERR(gti, "sysfs_create_link() failed for vendor, ret=%d!\n", + ret); + } } if (gti->vendor_input_dev) { ret = sysfs_create_link(>i->dev->kobj, >i->vendor_input_dev->dev.kobj, "vendor_input"); - if (ret) - GOOG_ERR("sysfs_create_link() failed for vendor_input, ret=%d!\n", + if (ret) { + GOOG_ERR(gti, "sysfs_create_link() failed for vendor_input, ret=%d!\n", ret); + } } } } @@ -2591,11 +3628,22 @@ struct goog_touch_interface *goog_touch_interface_probe( } if (gti && gti->dev) { + goog_init_proc(gti); + goog_init_options(gti, options); + goog_offload_probe(gti); + /* + * goog_init_input() needs the offload.cap initialization by goog_offload_probe(). + */ + goog_init_input(gti); + goog_register_tbn(gti); goog_pm_probe(gti); + register_panel_bridge(gti); + goog_init_variable_report_rate(gti); + goog_update_fw_settings(gti); ret = sysfs_create_group(>i->dev->kobj, &goog_attr_group); if (ret) - GOOG_ERR("sysfs_create_group() failed, ret= %d!\n", ret); + GOOG_ERR(gti, "sysfs_create_group() failed, ret= %d!\n", ret); } return gti; @@ -2607,34 +3655,40 @@ int goog_touch_interface_remove(struct goog_touch_interface *gti) if (!gti) return -ENODEV; - if (gti->tbn_enable && gti->tbn_register_mask) - unregister_tbn(>i->tbn_register_mask); - - unregister_panel_bridge(>i->panel_bridge); - - if (gti->vendor_dev) - sysfs_remove_link(>i->dev->kobj, "vendor"); - if (gti->vendor_input_dev) - sysfs_remove_link(>i->dev->kobj, "vendor_input"); + if (gti->dev) { + sysfs_remove_group(>i->dev->kobj, &goog_attr_group); + if (gti->vendor_dev) + sysfs_remove_link(>i->dev->kobj, "vendor"); + if (gti->vendor_input_dev) + sysfs_remove_link(>i->dev->kobj, "vendor_input"); + device_destroy(gti_class, gti->dev_id); + gti->dev = NULL; + gti_dev_num--; + } if (gti_class) { unregister_chrdev_region(gti->dev_id, 1); - device_destroy(gti_class, gti->dev_id); - gti_dev_num--; + if (!gti_dev_num) { + proc_remove(gti_proc_dir_root); + gti_proc_dir_root = NULL; + class_destroy(gti_class); + gti_class = NULL; + } } + unregister_panel_bridge(>i->panel_bridge); goog_pm_remove(gti); - gti->offload_enable = false; - gti->v4l2_enable = false; + if (gti->tbn_enabled && gti->tbn_register_mask) + unregister_tbn(>i->tbn_register_mask); + + gti->offload_enabled = false; + gti->v4l2_enabled = false; goog_offload_remove(gti); heatmap_remove(>i->v4l2); devm_kfree(gti->vendor_dev, gti->heatmap_buf); devm_kfree(gti->vendor_dev, gti); - if (gti_class && !gti_dev_num) - class_destroy(gti_class); - return 0; } EXPORT_SYMBOL(goog_touch_interface_remove); diff --git a/goog_touch_interface.h b/goog_touch_interface.h index 16a8abf..09f8245 100644 --- a/goog_touch_interface.h +++ b/goog_touch_interface.h @@ -12,32 +12,28 @@ #include <drm/drm_bridge.h> #include <drm/drm_connector.h> #include <linux/kfifo.h> +#include <linux/pm_qos.h> #include "heatmap.h" #include "touch_offload.h" #include "uapi/input/touch_offload.h" -#if IS_ENABLED(CONFIG_VH_SYSTRACE) -#include <trace/hooks/systrace.h> -#else -#define ATRACE_BEGIN(f) -#define ATRACE_END() -#endif - -#define GOOG_LOG_NAME "GTI" -#define GOOG_DBG(fmt, args...) pr_debug("[%s] %s: " fmt, GOOG_LOG_NAME,\ +#define GTI_NAME "goog_touch_interface" +#define GOOG_LOG_NAME(gti) ((gti && gti->dev) ? dev_name(gti->dev) : "GTI") +#define GOOG_DBG(gti, fmt, args...) pr_debug("[%s] %s: " fmt, GOOG_LOG_NAME(gti),\ __func__, ##args) -#define GOOG_LOG(fmt, args...) pr_info("[%s] %s: " fmt, GOOG_LOG_NAME,\ +#define GOOG_LOG(gti, fmt, args...) pr_info("[%s] " fmt, GOOG_LOG_NAME(gti), ##args) +#define GOOG_INFO(gti, fmt, args...) pr_info("[%s] %s: " fmt, GOOG_LOG_NAME(gti),\ __func__, ##args) -#define GOOG_WARN(fmt, args...) pr_warn("[%s] %s: " fmt, GOOG_LOG_NAME,\ +#define GOOG_WARN(gti, fmt, args...) pr_warn("[%s] %s: " fmt, GOOG_LOG_NAME(gti),\ __func__, ##args) -#define GOOG_ERR(fmt, args...) pr_err("[%s] %s: " fmt, GOOG_LOG_NAME,\ +#define GOOG_ERR(gti, fmt, args...) pr_err("[%s] %s: " fmt, GOOG_LOG_NAME(gti),\ __func__, ##args) #define MAX_SLOTS 10 -#define KTIME_RELEASE_ALL (ktime_set(0, 0)) #define GTI_DEBUG_KFIFO_LEN 4 /* must be power of 2. */ +#define GTI_SENSOR_2D_OUT_FORMAT_WIDTH(size) ((size > (PAGE_SIZE * sizeof(s16) / 6)) ? 1 : 5) /*----------------------------------------------------------------------------- * enums. */ @@ -51,6 +47,9 @@ enum gti_cmd_type : u32 { /* GTI_CMD_GET operations. */ GTI_CMD_GET_OPS_START = 0x200, + GTI_CMD_GET_CONTEXT_DRIVER, + GTI_CMD_GET_CONTEXT_STYLUS, + GTI_CMD_GET_COORD_FILTER_ENABLED, GTI_CMD_GET_FW_VERSION, GTI_CMD_GET_GRIP_MODE, GTI_CMD_GET_IRQ_MODE, @@ -59,6 +58,7 @@ enum gti_cmd_type : u32 { GTI_CMD_GET_SCREEN_PROTECTOR_MODE, GTI_CMD_GET_SENSING_MODE, GTI_CMD_GET_SENSOR_DATA, + GTI_CMD_GET_SENSOR_DATA_MANUAL, /* GTI_CMD_NOTIFY operations. */ GTI_CMD_NOTIFY_OPS_START = 0x300, @@ -68,10 +68,12 @@ enum gti_cmd_type : u32 { /* GTI_CMD_SET operations. */ GTI_CMD_SET_OPS_START = 0x400, GTI_CMD_SET_CONTINUOUS_REPORT, + GTI_CMD_SET_COORD_FILTER_ENABLED, GTI_CMD_SET_GRIP_MODE, GTI_CMD_SET_HEATMAP_ENABLED, GTI_CMD_SET_IRQ_MODE, GTI_CMD_SET_PALM_MODE, + GTI_CMD_SET_REPORT_RATE, GTI_CMD_SET_SCAN_MODE, GTI_CMD_SET_SCREEN_PROTECTOR_MODE, GTI_CMD_SET_SENSING_MODE, @@ -83,6 +85,11 @@ enum gti_continuous_report_setting : u32 { GTI_CONTINUOUS_REPORT_DRIVER_DEFAULT, }; +enum gti_coord_filter_setting : u32 { + GTI_COORD_FILTER_DISABLE = 0, + GTI_COORD_FILTER_ENABLE, +}; + enum gti_display_state_setting : u32 { GTI_DISPLAY_STATE_OFF = 0, GTI_DISPLAY_STATE_ON, @@ -144,8 +151,8 @@ enum gti_ping_mode : u32 { }; enum gti_pm_state : u32 { - GTI_PM_RESUME = 0, - GTI_PM_SUSPEND, + GTI_PM_SUSPEND = 0, + GTI_PM_RESUME, }; #define GTI_PM_WAKELOCK_TYPE_LOCK_MASK 0xFFFF @@ -159,6 +166,19 @@ enum gti_pm_wakelock_type : u32 { GTI_PM_WAKELOCK_TYPE_SYSFS = (1 << 3), GTI_PM_WAKELOCK_TYPE_FORCE_ACTIVE = (1 << 4), GTI_PM_WAKELOCK_TYPE_BUGREPORT = (1 << 5), + GTI_PM_WAKELOCK_TYPE_OFFLOAD_REPORT = (1 << 6), + GTI_PM_WAKELOCK_TYPE_SENSOR_DATA = (1 << 7), + GTI_PM_WAKELOCK_TYPE_FW_SETTINGS = (1 << 8), +}; + +enum gti_proc_type : u32 { + GTI_PROC_MS_BASE, + GTI_PROC_MS_DIFF, + GTI_PROC_MS_RAW, + GTI_PROC_SS_BASE, + GTI_PROC_SS_DIFF, + GTI_PROC_SS_RAW, + GTI_PROC_NUM, }; enum gti_reset_mode : u32 { @@ -221,18 +241,15 @@ enum gti_sensor_data_type : u32 { TOUCH_SCAN_TYPE_SELF | TOUCH_DATA_TYPE_BASELINE, }; -enum gti_vendor_dev_pm_state : u32 { - GTI_VENDOR_DEV_RESUME = 0, - GTI_VENDOR_DEV_SUSPEND, -}; - enum gti_fw_status : u32 { - GTI_FW_STATUE_RESET = 0, - GTI_FW_STATUE_PALM_ENTER, - GTI_FW_STATUE_PALM_EXIT, - GTI_FW_STATUE_GRIP_ENTER, - GTI_FW_STATUE_GRIP_EXIT, - GTI_FW_STATUE_NOISE_MODE, + GTI_FW_STATUS_RESET = 0, + GTI_FW_STATUS_PALM_ENTER, + GTI_FW_STATUS_PALM_EXIT, + GTI_FW_STATUS_GRIP_ENTER, + GTI_FW_STATUS_GRIP_EXIT, + GTI_FW_STATUS_WATER_ENTER, + GTI_FW_STATUS_WATER_EXIT, + GTI_FW_STATUS_NOISE_MODE, }; enum gti_noise_mode_level : u8 { @@ -246,21 +263,76 @@ enum gti_noise_mode_level : u8 { * Structures. */ +struct gti_context_changed { + union { + struct { + u32 screen_state : 1; + u32 display_refresh_rate : 1; + u32 touch_report_rate : 1; + u32 noise_state : 1; + u32 water_mode : 1; + u32 charger_state : 1; + u32 hinge_angle : 1; + u32 offload_timestamp : 1; + }; + u32 value; + }; +}; + +struct gti_context_driver_cmd { + struct gti_context_changed context_changed; + + u8 screen_state; + u8 display_refresh_rate; + u8 touch_report_rate; + u8 noise_state; + u8 water_mode; + u8 charger_state; + s16 hinge_angle; + + ktime_t offload_timestamp; +}; + +struct gti_context_stylus_cmd { + struct { + u32 coords : 1; + u32 coords_timestamp : 1; + u32 pen_paired : 1; + u32 pen_active : 1; + } contents; + struct TouchOffloadCoord pen_offload_coord; + ktime_t pen_offload_coord_timestamp; + u8 pen_paired; + u8 pen_active; +}; + struct gti_continuous_report_cmd { enum gti_continuous_report_setting setting; }; struct gti_debug_coord { ktime_t time; + u64 irq_index; struct TouchOffloadCoord coord; }; +struct gti_debug_health_check { + ktime_t irq_time; + u64 irq_index; + u64 input_index; + unsigned long slot_bit_active; +}; + struct gti_debug_input { int slot; struct gti_debug_coord pressed; struct gti_debug_coord released; }; +struct gti_coord_filter_cmd { + enum gti_coord_filter_setting setting; +}; + struct gti_display_state_cmd { enum gti_display_state_setting setting; }; @@ -293,6 +365,10 @@ struct gti_ping_cmd { enum gti_ping_mode setting; }; +struct gti_report_rate_cmd { + u32 setting; +}; + struct gti_reset_cmd { enum gti_reset_mode setting; }; @@ -322,7 +398,10 @@ struct gti_sensor_data_cmd { /** * struct gti_union_cmd_data - GTI commands to vendor driver. + * @context_driver_cmd: command to update touch offload driver context. + * @context_stylus_cmd: command to update touch offload stylus context. * @continuous_report_cmd: command to set continuous reporting. + * @coord_filter_cmd: command to set/get coordinate filter enabled. * @display_state_cmd: command to notify display state. * @display_vrefresh_cmd: command to notify display vertical refresh rate. * @fw_version_cmd: command to get fw version. @@ -331,15 +410,20 @@ struct gti_sensor_data_cmd { * @irq_cmd: command to set/get irq mode. * @palm_cmd: command to set/get palm mode. * @ping_cmd: command to ping T-IC. + * @report_rate_cmd: command to change touch report rate. * @reset_cmd: command to reset T-IC. * @scan_cmd: command to set/get scan mode. * @screen_protector_mode_cmd: command to set/get screen protector mode. * @selftest_cmd: command to do self-test. * @sensing_cmd: command to set/set sensing mode. * @sensor_data_cmd: command to get sensor data. + * @manual_sensor_data_cmd: command to get sensor data manually. */ struct gti_union_cmd_data { + struct gti_context_driver_cmd context_driver_cmd; + struct gti_context_stylus_cmd context_stylus_cmd; struct gti_continuous_report_cmd continuous_report_cmd; + struct gti_coord_filter_cmd coord_filter_cmd; struct gti_display_state_cmd display_state_cmd; struct gti_display_vrefresh_cmd display_vrefresh_cmd; struct gti_fw_version_cmd fw_version_cmd; @@ -348,12 +432,14 @@ struct gti_union_cmd_data { struct gti_irq_cmd irq_cmd; struct gti_palm_cmd palm_cmd; struct gti_ping_cmd ping_cmd; + struct gti_report_rate_cmd report_rate_cmd; struct gti_reset_cmd reset_cmd; struct gti_scan_cmd scan_cmd; struct gti_screen_protector_mode_cmd screen_protector_mode_cmd; struct gti_selftest_cmd selftest_cmd; struct gti_sensing_cmd sensing_cmd; struct gti_sensor_data_cmd sensor_data_cmd; + struct gti_sensor_data_cmd manual_sensor_data_cmd; }; /** @@ -362,10 +448,14 @@ struct gti_union_cmd_data { */ struct gti_fw_status_data { enum gti_noise_mode_level noise_level; + u8 water_mode; }; /** * struct gti_optional_configuration - optional configuration by vendor driver. + * @get_context_driver: vendor driver operation to update touch offload driver context. + * @get_context_stylus: vendor driver operation to update touch offload stylus context. + * @get_coord_filter_enabled: vendor driver operation to get the coordinate filter enabled. * @get_fw_version: vendor driver operation to get fw version info. * @get_grip_mode: vendor driver operation to get the grip mode setting. * @get_irq_mode: vendor driver operation to get irq mode setting. @@ -381,22 +471,28 @@ struct gti_fw_status_data { * @reset: vendor driver operation to exec reset. * @selftest: vendor driver operation to exec self-test. * @set_continuous_report: vendor driver operation to apply the continuous reporting setting. + * @set_coord_filter_enabled: vendor driver operation to apply the coordinate filter enabled. * @set_grip_mode: vendor driver operation to apply the grip setting. * @set_heatmap_enabled: vendor driver operation to apply the heatmap setting. * @set_irq_mode: vendor driver operation to apply the irq setting. * @set_palm_mode: vendor driver operation to apply the palm setting. + * @set_report_rate: driver operation to set touch report rate. * @set_scan_mode: vendor driver operation to set scan mode. * @set_screen_protector_mode: vendor driver operation to set screen protector mode. * @set_sensing_mode: vendor driver operation to set sensing mode. */ struct gti_optional_configuration { + int (*get_context_driver)(void *private_data, struct gti_context_driver_cmd *cmd); + int (*get_context_stylus)(void *private_data, struct gti_context_stylus_cmd *cmd); + int (*get_coord_filter_enabled)(void *private_data, struct gti_coord_filter_cmd *cmd); int (*get_fw_version)(void *private_data, struct gti_fw_version_cmd *cmd); int (*get_grip_mode)(void *private_data, struct gti_grip_cmd *cmd); int (*get_irq_mode)(void *private_data, struct gti_irq_cmd *cmd); int (*get_mutual_sensor_data)(void *private_data, struct gti_sensor_data_cmd *cmd); int (*get_palm_mode)(void *private_data, struct gti_palm_cmd *cmd); int (*get_scan_mode)(void *private_data, struct gti_scan_cmd *cmd); - int (*get_screen_protector_mode)(void *private_data, struct gti_screen_protector_mode_cmd *cmd); + int (*get_screen_protector_mode)(void *private_data, + struct gti_screen_protector_mode_cmd *cmd); int (*get_self_sensor_data)(void *private_data, struct gti_sensor_data_cmd *cmd); int (*get_sensing_mode)(void *private_data, struct gti_sensing_cmd *cmd); int (*notify_display_state)(void *private_data, struct gti_display_state_cmd *cmd); @@ -405,36 +501,41 @@ struct gti_optional_configuration { int (*reset)(void *private_data, struct gti_reset_cmd *cmd); int (*selftest)(void *private_data, struct gti_selftest_cmd *cmd); int (*set_continuous_report)(void *private_data, struct gti_continuous_report_cmd *cmd); + int (*set_coord_filter_enabled)(void *private_data, struct gti_coord_filter_cmd *cmd); int (*set_grip_mode)(void *private_data, struct gti_grip_cmd *cmd); int (*set_heatmap_enabled)(void *private_data, struct gti_heatmap_cmd *cmd); int (*set_irq_mode)(void *private_data, struct gti_irq_cmd *cmd); int (*set_palm_mode)(void *private_data, struct gti_palm_cmd *cmd); + int (*set_report_rate)(void *private_data, struct gti_report_rate_cmd *cmd); int (*set_scan_mode)(void *private_data, struct gti_scan_cmd *cmd); - int (*set_screen_protector_mode)(void *private_data, struct gti_screen_protector_mode_cmd *cmd); + int (*set_screen_protector_mode)(void *private_data, + struct gti_screen_protector_mode_cmd *cmd); int (*set_sensing_mode)(void *private_data, struct gti_sensing_cmd *cmd); }; /** * struct gti_pm - power manager for GTI. - * @suspend_work: a work to run suspend. - * @resume_work: a work to run resume. + * @state_update_work: a work to update pm state. * @event_wq: a work queue to run suspend/resume work. - * @bus_resumed: a completion for waiting for resume is done. * @locks: the lock state. * @lock_mutex: protect the lock state. * @state: GTI pm state. + * @new_state: New GTI pm state to be updated to. + * @enabled: Boolean value to represent if GTI PM is active. + * @update_state: Boolean value if state needs to be updated. * @resume: callback for notifying resume. * @suspend: callback for notifying suspend. */ struct gti_pm { - struct work_struct suspend_work; - struct work_struct resume_work; + struct work_struct state_update_work; struct workqueue_struct *event_wq; - struct completion bus_resumed; u32 locks; struct mutex lock_mutex; enum gti_pm_state state; + enum gti_pm_state new_state; + bool enabled; + bool update_state; int (*resume)(struct device *dev); int (*suspend)(struct device *dev); @@ -448,28 +549,50 @@ struct gti_pm { * @dev: pointer to struct device that used by google touch interface driver. * @options: optional configuration that could apply by vendor driver. * @input_lock: protect the input report between non-offload and offload. + * @input_process_lock: protect heatmap reading and frame reserving. * @offload: struct that used by touch offload. * @offload_frame: reserved frame that used by touch offload. * @v4l2: struct that used by v4l2. * @panel_bridge: struct that used to register panel bridge notification. * @connector: struct that used to get panel status. * @cmd: struct that used by vendor default handler. + * @proc_dir: struct that used for procfs. + * @proc_heatmap: struct that used for heatmap procfs. * @input_timestamp: input timestamp from touch vendor driver. * @mf_downtime: timestamp for motion filter control. * @display_vrefresh: display vrefresh in Hz. * @mf_mode: current motion filter mode. * @mf_state: current motion filter state. + * @vrr_enabled: variable touch report rate is enabled or not. + * @report_rate_table_size: report rate table size from device tree. + * @touch_report_rate_table: touch report rate table parsed from device tree. + * @display_refresh_rate_table: display refresh rate table parsed from device tree. + * @report_rate_setting: current touch report rate. + * @report_rate_setting_next: next touch report rate going be set. + * @set_report_rate_work: delayed work for setting report rate. + * @increase_report_rate_delay: delayed work will be start after a delay in seconds. + * @decrease_report_rate_delay: delayed work will be start after a delay in seconds. * @screen_protector_mode_setting: the setting of screen protector mode. * @tbn_register_mask: the tbn_mask that used to request/release touch bus. * @pm: struct that used by gti pm. + * @pm_qos_req: struct that used by pm qos. + * @fw_status: firmware status such as water_mode, noise_level, etc. + * @context_changed: flags that indicate driver status changing. * @panel_is_lp_mode: display is in low power mode. - * @force_legacy_report: force to directly report input by kernel input API. - * @offload_enable: touch offload is enabled or not. - * @v4l2_enable: v4l2 is enabled or not. - * @tbn_enable: tbn is enabled or not. + * @offload_enabled: touch offload is enabled or not. + * @v4l2_enabled: v4l2 is enabled or not. + * @tbn_enabled: tbn is enabled or not. + * @coord_filter_enabled: coordinate filter is enabled or not. * @input_timestamp_changed: input timestamp changed from touch vendor driver. + * @ignore_grip_update: Ignore fw_grip status updates made on offload state change. * @default_grip_enabled: the grip default setting. + * @ignore_palm_update: Ignore fw_palm status updates made on offload state change. * @default_palm_enabled: the palm default setting. + * @ignore_coord_filter_update: Ignore fw_coordinate_filter status updates. + * @fw_coord_filter_enabled: the current setting of coordinate filter. + * @default_coord_filter_enabled: the default setting of coordinate filter. + * @lptw_triggered: LPTW is triggered or not. + * @ignore_force_active: Ignore the force_active sysfs request. * @offload_id: id that used by touch offload. * @heatmap_buf: heatmap buffer that used by v4l2. * @heatmap_buf_size: heatmap buffer size that used by v4l2. @@ -478,10 +601,19 @@ struct gti_pm { * @slot_bit_changed: bitmap of slot state changed for this input process cycle. * @slot_bit_active: bitmap of active slot during GTI lifecycle. * @dev_id: dev_t used for google interface driver. + * @charger_state: indicates a USB charger is connected. + * @charger_notifier: notifier for power_supply updates. + * @irq_index: irq count that handle by GTI. + * @input_index: the count of slot bit changed during goog_input_process(). + * @vendor_irq_handler: irq handler that register by vendor driver. + * @vendor_irq_thread_fn: irq thread function that register by vendor driver. + * @vendor_irq_cookie: irq cookie that register by vendor driver. * @vendor_default_handler: touch vendor driver default operation. - * @released_count: finger up count. + * @released_index: finger up count. * @debug_input: struct that used to debug input. - * @debug_fifo: struct that used to debug input. + * @debug_fifo_input: kfifo struct to track recent coordinate report for input debug. + * @debug_hc: struct that used for the health check. + * @debug_fifo_hc: kfifo struct to track recent touch interrupt information for health check. */ struct goog_touch_interface { @@ -491,33 +623,58 @@ struct goog_touch_interface { struct device *dev; struct gti_optional_configuration options; struct mutex input_lock; + struct mutex input_process_lock; struct touch_offload_context offload; struct touch_offload_frame *offload_frame; struct v4l2_heatmap v4l2; struct drm_bridge panel_bridge; struct drm_connector *connector; struct gti_union_cmd_data cmd; + struct proc_dir_entry *proc_dir; + struct proc_dir_entry *proc_heatmap[GTI_PROC_NUM]; ktime_t input_timestamp; ktime_t mf_downtime; + bool vrr_enabled; + int report_rate_table_size; + u32 *display_refresh_rate_table; + u32 *touch_report_rate_table; + u32 report_rate_setting; + u32 report_rate_setting_next; + struct delayed_work set_report_rate_work; + u32 increase_report_rate_delay; + u32 decrease_report_rate_delay; + int display_vrefresh; + enum gti_display_state_setting display_state; enum gti_mf_mode mf_mode; enum gti_mf_state mf_state; enum gti_screen_protector_mode screen_protector_mode_setting; u32 tbn_register_mask; struct gti_pm pm; + struct pm_qos_request pm_qos_req; + + struct gti_fw_status_data fw_status; + struct gti_context_changed context_changed; bool panel_is_lp_mode; - bool force_legacy_report; - bool offload_enable; - bool v4l2_enable; - bool tbn_enable; + bool offload_enabled; + bool v4l2_enabled; + bool tbn_enabled; + bool coord_filter_enabled; bool input_timestamp_changed; + bool ignore_grip_update; bool default_grip_enabled; + bool ignore_palm_update; bool default_palm_enabled; + bool ignore_coord_filter_update; + bool fw_coord_filter_enabled; + bool default_coord_filter_enabled; + bool lptw_triggered; + bool ignore_force_active; union { - u8 offload_id_byte[4]; - u32 offload_id; + u8 offload_id_byte[4]; + u32 offload_id; }; u8 *heatmap_buf; u32 heatmap_buf_size; @@ -527,19 +684,30 @@ struct goog_touch_interface { unsigned long slot_bit_active; dev_t dev_id; + u8 charger_state; + struct notifier_block charger_notifier; + + u64 irq_index; + u64 input_index; + irq_handler_t vendor_irq_handler; + irq_handler_t vendor_irq_thread_fn; + void *vendor_irq_cookie; + int (*vendor_default_handler)(void *private_data, enum gti_cmd_type cmd_type, struct gti_union_cmd_data *cmd); /* Debug used. */ - unsigned long released_count; + u64 released_index; struct gti_debug_input debug_input[MAX_SLOTS]; - DECLARE_KFIFO(debug_fifo, struct gti_debug_input, GTI_DEBUG_KFIFO_LEN); + DECLARE_KFIFO(debug_fifo_input, struct gti_debug_input, GTI_DEBUG_KFIFO_LEN); + struct gti_debug_health_check debug_hc; + DECLARE_KFIFO(debug_fifo_hc, struct gti_debug_health_check, GTI_DEBUG_KFIFO_LEN); }; /*----------------------------------------------------------------------------- * Forward declarations. */ - +inline bool goog_check_spi_dma_enabled(struct spi_device *spi_dev); inline bool goog_input_legacy_report(struct goog_touch_interface *gti); inline void goog_input_lock(struct goog_touch_interface *gti); inline void goog_input_unlock(struct goog_touch_interface *gti); @@ -559,9 +727,17 @@ inline void goog_input_report_key( struct goog_touch_interface *gti, struct input_dev *dev, unsigned int code, int value); inline void goog_input_sync(struct goog_touch_interface *gti, struct input_dev *dev); +inline int goog_devm_request_threaded_irq(struct goog_touch_interface *gti, + struct device *dev, unsigned int irq, + irq_handler_t handler, irq_handler_t thread_fn, + unsigned long irqflags, const char *devname, + void *dev_id); +inline int goog_request_threaded_irq(struct goog_touch_interface *gti, + unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, + unsigned long irqflags, const char *devname, void *dev_id); int goog_process_vendor_cmd(struct goog_touch_interface *gti, enum gti_cmd_type cmd_type); -int goog_input_process(struct goog_touch_interface *gti); +int goog_input_process(struct goog_touch_interface *gti, bool reset_data); struct goog_touch_interface *goog_touch_interface_probe( void *private_data, struct device *dev, @@ -571,8 +747,12 @@ struct goog_touch_interface *goog_touch_interface_probe( struct gti_optional_configuration *options); int goog_touch_interface_remove(struct goog_touch_interface *gti); +int goog_pm_wake_lock_nosync(struct goog_touch_interface *gti, + enum gti_pm_wakelock_type type, bool skip_pm_resume); int goog_pm_wake_lock(struct goog_touch_interface *gti, enum gti_pm_wakelock_type type, bool skip_pm_resume); +int goog_pm_wake_unlock_nosync(struct goog_touch_interface *gti, + enum gti_pm_wakelock_type type); int goog_pm_wake_unlock(struct goog_touch_interface *gti, enum gti_pm_wakelock_type type); bool goog_pm_wake_check_locked(struct goog_touch_interface *gti, @@ -584,5 +764,10 @@ int goog_pm_unregister_notification(struct goog_touch_interface *gti); void goog_notify_fw_status_changed(struct goog_touch_interface *gti, enum gti_fw_status status, struct gti_fw_status_data* data); +void gti_debug_hc_dump(struct goog_touch_interface *gti); +void gti_debug_input_dump(struct goog_touch_interface *gti); + +int goog_get_lptw_triggered(struct goog_touch_interface *gti); + #endif // _GOOG_TOUCH_INTERFACE_ diff --git a/goog_touch_interface_nop.h b/goog_touch_interface_nop.h index 4483749..0528e37 100644 --- a/goog_touch_interface_nop.h +++ b/goog_touch_interface_nop.h @@ -9,8 +9,6 @@ #include <linux/input/mt.h> -#define KTIME_RELEASE_ALL (ktime_set(0, 0)) - enum gti_cmd_type : u32{ GTI_CMD_NOP, }; @@ -380,6 +380,9 @@ int heatmap_probe(struct v4l2_heatmap *v4l2) return 0; err_video_device_release: + mutex_lock(&v4l2->lock); + vb2_queue_release(&v4l2->queue); + mutex_unlock(&v4l2->lock); video_device_release(&v4l2->vdev); err_unreg_v4l2: @@ -395,6 +398,11 @@ void heatmap_remove(struct v4l2_heatmap *v4l2) { if (v4l2->frame) { video_unregister_device(&v4l2->vdev); + + mutex_lock(&v4l2->lock); + vb2_queue_release(&v4l2->queue); + mutex_unlock(&v4l2->lock); + v4l2_device_unregister(&v4l2->device); devm_kfree(v4l2->parent_dev, v4l2->frame); v4l2->frame = NULL; @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _HEATMAP_H_ +#define _HEATMAP_H_ + #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> @@ -52,4 +55,6 @@ void heatmap_remove(struct v4l2_heatmap *v4l2); * This function should be called from the driver. Internally, it will call * read_frame(..) provided by the driver to read the actual data. */ -void heatmap_read(struct v4l2_heatmap *v4l2, uint64_t timestamp);
\ No newline at end of file +void heatmap_read(struct v4l2_heatmap *v4l2, uint64_t timestamp); + +#endif // _HEATMAP_H_ diff --git a/include/uapi/input/touch_offload.h b/include/uapi/input/touch_offload.h index 4a10ba1..eb8af30 100644 --- a/include/uapi/input/touch_offload.h +++ b/include/uapi/input/touch_offload.h @@ -61,6 +61,7 @@ * filter_palm - driver supports disabling underlying palm rejection * num_sensitivity_settings - number of sensitivity options provided * auto_reporting - report heatmap when screen is not touched + * coord_filter - driver supports disabling underlying coordinate filter */ struct TouchOffloadCaps { /* Version info */ @@ -95,7 +96,8 @@ struct TouchOffloadCaps { __u8 filter_palm; __u8 num_sensitivity_settings; __u8 auto_reporting; - __u8 reserved4[32]; + __u8 coord_filter; + __u8 reserved4[31]; } __attribute__((packed)); /* TouchOffloadConfig @@ -107,6 +109,7 @@ struct TouchOffloadCaps { * filter_palm - enable underlying palm rejection * sensitivity_setting - selected sensitivity * auto_reporting - enable reporting when screen is not touched + * coord_filter - enable underlying coordinate filter * read_coords - allocate a channel to coordinate data * mutual_data_types - bitfield of mutual data types to collect * self_data_types - bitfield of self data types to collect @@ -122,7 +125,8 @@ struct TouchOffloadConfig { __u8 filter_palm; __u8 sensitivity_setting; __u8 auto_reporting; - __u8 reserved1[16]; + __u8 coord_filter; + __u8 reserved1[15]; /* Data to read */ __u8 read_coords; diff --git a/touch_bus_negotiator.c b/touch_bus_negotiator.c index 375095a..51898a0 100644 --- a/touch_bus_negotiator.c +++ b/touch_bus_negotiator.c @@ -17,20 +17,26 @@ #include <linux/delay.h> #include "touch_bus_negotiator.h" +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +#include <uapi/linux/sched/types.h> +#include "aoc_tbn_service_dev.h" +#endif + #define TBN_MODULE_NAME "touch_bus_negotiator" +#define TBN_AOC_CHANNEL_THREAD_NAME "tbn_aoc_channel" -static struct tbn_context *tbn_context = NULL; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +static void handle_tbn_event_response(struct tbn_context *tbn, + struct TbnEventResponse *response); +#endif -enum tbn_operation { - AP_RELEASE_BUS, - AP_REQUEST_BUS, -}; +static struct tbn_context *tbn_context; static irqreturn_t tbn_aoc2ap_irq_thread(int irq, void *ptr) { struct tbn_context *tbn = ptr; - dev_info(tbn_context->dev, "%s: bus_released:%d bus_requested:%d.\n", __func__, + dev_info(tbn->dev, "%s: bus_released:%d bus_requested:%d.\n", __func__, completion_done(&tbn->bus_released), completion_done(&tbn->bus_requested)); if (completion_done(&tbn->bus_released) && completion_done(&tbn->bus_requested)) @@ -65,7 +71,113 @@ static irqreturn_t tbn_aoc2ap_irq_thread(int irq, void *ptr) return IRQ_HANDLED; } -int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) +static int aoc_channel_kthread(void *data) +{ + struct tbn_context *tbn = data; + struct TbnEventResponse resp; + ssize_t len; + bool service_ready = false; + + while (!kthread_should_stop()) { + if (service_ready != aoc_tbn_service_ready()) { + service_ready = !service_ready; + dev_info(tbn->dev, "%s: AOC TBN service is %s.\n", + __func__, service_ready ? "ready" : "not ready"); + } + + if (!service_ready) { + msleep(1000); + continue; + } + + len = aoc_tbn_service_read(&resp, sizeof(resp)); + if (len < 0) { + dev_err(tbn->dev, "%s: failed to read message, err: %d\n", + __func__, len); + msleep(1000); + continue; + } + + if (kthread_should_stop()) { + break; + } + + if (len == sizeof(resp)) { + handle_tbn_event_response(tbn, &resp); + } + } + + return 0; +} + +static void handle_tbn_event_response(struct tbn_context *tbn, + struct TbnEventResponse *response) +{ + mutex_lock(&tbn->event_lock); + + if (response->id != tbn->event.id) { + dev_err(tbn->dev, + "%s: receive wrong response, id: %d, expected id: %d, " + "bus_released:%d bus_requested:%d.\n", + __func__, response->id, tbn->event.id, + completion_done(&tbn->bus_released), + completion_done(&tbn->bus_requested)); + goto exit; + } + + if (response->err != 0) { + dev_err(tbn->dev, "%s: send tbn event failed, err %d!\n", + __func__, response->err); + tbn->event_resp.err = response->err; + } else { + tbn->event_resp.lptw_triggered = response->lptw_triggered; + } + + if (response->operation == TBN_OPERATION_AP_REQUEST_BUS) { + complete_all(&tbn->bus_requested); + } else if (response->operation == TBN_OPERATION_AP_RELEASE_BUS) { + complete_all(&tbn->bus_released); + } else { + dev_err(tbn->dev, "%s: response unknown operation, op: %d!\n", + __func__, response->operation); + } + +exit: + mutex_unlock(&tbn->event_lock); +} + +static void send_tbn_event(struct tbn_context *tbn, enum TbnOperation operation) +{ + ssize_t len; + int retry = 3; + + if (!aoc_tbn_service_ready()) { + dev_err(tbn_context->dev, "%s: AOC TBN service is not ready.\n", + __func__); + return; + } + + mutex_lock(&tbn->event_lock); + + tbn->event.operation = operation; + tbn->event.id++; + + while (retry) { + len = aoc_tbn_service_write(&tbn->event, sizeof(tbn->event)); + if (len == sizeof(tbn->event)) { + break; + } + dev_err(tbn_context->dev, "%s: failed to send TBN event, retry: %d.\n", + __func__, retry); + retry--; + } + + mutex_unlock(&tbn->event_lock); +} +#endif + +int tbn_handshaking(struct tbn_context *tbn, enum TbnOperation operation) { struct completion *wait_for_completion; enum tbn_bus_owner bus_owner; @@ -74,44 +186,87 @@ int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) const char *msg; int ret = 0; - if (!tbn || tbn->registered_mask == 0) - return 0; + if (!tbn || tbn->registered_mask == 0) { + dev_err(tbn_context->dev, "%s: tbn is not ready to serve.\n", __func__); + return -EINVAL; + } - if (operation == AP_REQUEST_BUS) { + if (operation == TBN_OPERATION_AP_REQUEST_BUS) { wait_for_completion = &tbn->bus_requested; bus_owner = TBN_BUS_OWNER_AP; irq_type = IRQF_TRIGGER_FALLING; timeout = TBN_REQUEST_BUS_TIMEOUT_MS; msg = "request"; - } else { + } else if (operation == TBN_OPERATION_AP_RELEASE_BUS) { wait_for_completion = &tbn->bus_released; bus_owner = TBN_BUS_OWNER_AOC; irq_type = IRQF_TRIGGER_RISING; timeout = TBN_RELEASE_BUS_TIMEOUT_MS; msg = "release"; + } else { + dev_err(tbn_context->dev, "%s: request unknown operation, op: %d.\n", + __func__, operation); + return -EINVAL; } - reinit_completion(wait_for_completion); - if (tbn->mode == TBN_MODE_GPIO) { + int ap2aoc_val_org = gpio_get_value(tbn->ap2aoc_gpio); + int aoc2ap_val_org = gpio_get_value(tbn->aoc2ap_gpio); + + reinit_completion(wait_for_completion); + irq_set_irq_type(tbn->aoc2ap_irq, irq_type); enable_irq(tbn->aoc2ap_irq); gpio_direction_output(tbn->ap2aoc_gpio, bus_owner); if (wait_for_completion_timeout(wait_for_completion, - msecs_to_jiffies(timeout)) == 0) { - dev_err(tbn->dev, "AP %s bus ... timeout!, aoc2ap_gpio=%d\n", - msg, gpio_get_value(tbn->aoc2ap_gpio)); + msecs_to_jiffies(timeout)) == 0) { + int ap2aoc_val = gpio_get_value(tbn->ap2aoc_gpio); + int aoc2ap_val = gpio_get_value(tbn->aoc2ap_gpio); + complete_all(wait_for_completion); - ret = -ETIMEDOUT; + if (bus_owner == aoc2ap_val) + ret = 0; + else + ret = -ETIMEDOUT; + dev_err(tbn->dev, "AP %s bus ... timeout!, ap2aoc_gpio(B:%d,A:%d)" + " aoc2ap_gpio(B:%d,A:%d), ret=%d\n", + msg, ap2aoc_val_org, ap2aoc_val, aoc2ap_val_org, + aoc2ap_val, ret); } else dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); disable_irq_nosync(tbn->aoc2ap_irq); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + tbn->event_resp.lptw_triggered = false; + tbn->event_resp.err = 0; + + reinit_completion(wait_for_completion); + + send_tbn_event(tbn, operation); + if (wait_for_completion_timeout(wait_for_completion, + msecs_to_jiffies(timeout)) == 0) { + dev_err(tbn->dev, "AP %s bus ... timeout!\n", msg); + complete_all(wait_for_completion); + ret = -ETIMEDOUT; + } else { + if (tbn->event_resp.err == 0) { + dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); + } else { + dev_info(tbn->dev, "AP %s bus ... failed!\n", msg); + ret = -EBUSY; + } + } +#endif + } else if (tbn->mode == TBN_MODE_MOCK) { + dev_info(tbn->dev, "AP %s bus ... SUCCESS!\n", msg); + } else { + ret = -EINVAL; } return ret; } -int tbn_request_bus(u32 dev_mask) +int tbn_request_bus_with_result(u32 dev_mask, bool *lptw_triggered) { int ret = 0; @@ -128,11 +283,13 @@ int tbn_request_bus(u32 dev_mask) } if (tbn_context->requested_dev_mask == 0) { - ret = tbn_handshaking(tbn_context, AP_REQUEST_BUS); + ret = tbn_handshaking(tbn_context, TBN_OPERATION_AP_REQUEST_BUS); + if ((ret == 0) && (lptw_triggered != NULL)) + *lptw_triggered = tbn_context->event_resp.lptw_triggered; } else { dev_dbg(tbn_context->dev, - "%s: Bus already requested, requested_dev_mask %#x dev_mask %#x.\n", - __func__, tbn_context->requested_dev_mask, dev_mask); + "%s: Bus already requested, requested_dev_mask %#x dev_mask %#x.\n", + __func__, tbn_context->requested_dev_mask, dev_mask); } tbn_context->requested_dev_mask |= dev_mask; @@ -140,6 +297,12 @@ int tbn_request_bus(u32 dev_mask) return ret; } +EXPORT_SYMBOL_GPL(tbn_request_bus_with_result); + +int tbn_request_bus(u32 dev_mask) +{ + return tbn_request_bus_with_result(dev_mask, NULL); +} EXPORT_SYMBOL_GPL(tbn_request_bus); int tbn_release_bus(u32 dev_mask) @@ -168,7 +331,7 @@ int tbn_release_bus(u32 dev_mask) /* Release the bus when the last requested_dev_mask bit releases. */ if (tbn_context->requested_dev_mask == dev_mask) { - ret = tbn_handshaking(tbn_context, AP_RELEASE_BUS); + ret = tbn_handshaking(tbn_context, TBN_OPERATION_AP_RELEASE_BUS); } else { dev_dbg(tbn_context->dev, "%s: Bus is still in use, requested_dev_mask %#x dev_mask %#x.\n", @@ -187,6 +350,8 @@ int register_tbn(u32 *output) { u32 i = 0; + *output = 0; + if (!tbn_context) { pr_warn("%s: tbn_context doesn't exist.", __func__); return 0; @@ -227,22 +392,30 @@ static int tbn_probe(struct platform_device *pdev) struct tbn_context *tbn = NULL; struct device_node *np = dev->of_node; int err = 0; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + struct sched_param param = { + .sched_priority = 10, + }; +#endif + tbn = devm_kzalloc(dev, sizeof(struct tbn_context), GFP_KERNEL); if (!tbn) goto failed; tbn->dev = dev; + tbn->event_resp.lptw_triggered = false; tbn_context = tbn; dev_set_drvdata(tbn->dev, tbn); if (of_property_read_u32(np, "tbn,max_devices", &tbn->max_devices)) tbn->max_devices = 1; - if (of_property_read_bool(np, "tbn,ap2aoc_gpio") && - of_property_read_bool(np, "tbn,aoc2ap_gpio")) { + err = of_property_read_u32(np, "tbn,mode", &tbn->mode); + if (err) tbn->mode = TBN_MODE_GPIO; + if (tbn->mode == TBN_MODE_GPIO) { tbn->ap2aoc_gpio = of_get_named_gpio(np, "tbn,ap2aoc_gpio", 0); if (gpio_is_valid(tbn->ap2aoc_gpio)) { err = devm_gpio_request_one(tbn->dev, tbn->ap2aoc_gpio, @@ -252,6 +425,11 @@ static int tbn_probe(struct platform_device *pdev) __func__, tbn->ap2aoc_gpio, err); goto failed; } + } else { + dev_err(tbn->dev, "%s: invalid ap2aoc_gpio %d!\n", + __func__, tbn->ap2aoc_gpio); + err = -EPROBE_DEFER; + goto failed; } tbn->aoc2ap_gpio = of_get_named_gpio(np, "tbn,aoc2ap_gpio", 0); @@ -279,10 +457,35 @@ static int tbn_probe(struct platform_device *pdev) } else { dev_err(tbn->dev, "%s: invalid aoc2ap_gpio %d!\n", __func__, tbn->aoc2ap_gpio); + err = -EPROBE_DEFER; goto failed; } + + dev_info(tbn->dev, + "%s: gpios(aoc2ap: %d ap2aoc: %d)\n", + __func__, tbn->aoc2ap_gpio, tbn->ap2aoc_gpio); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + mutex_init(&tbn->event_lock); + + tbn->aoc_channel_task = kthread_run(&aoc_channel_kthread, tbn, + TBN_AOC_CHANNEL_THREAD_NAME); + if (IS_ERR(tbn->aoc_channel_task)) { + err = PTR_ERR(tbn->aoc_channel_task); + goto failed; + } + + err = sched_setscheduler(tbn->aoc_channel_task, SCHED_FIFO, ¶m); + if (err != 0) { + goto failed; + } +#endif + } else if (tbn->mode == TBN_MODE_MOCK) { + err = 0; } else { - tbn->mode = TBN_MODE_DISABLED; + dev_err(tbn->dev, "bus negotiator: invalid mode: %d\n", tbn->mode); + err = -EINVAL; + goto failed; } mutex_init(&tbn->dev_mask_mutex); @@ -292,26 +495,33 @@ static int tbn_probe(struct platform_device *pdev) complete_all(&tbn->bus_requested); complete_all(&tbn->bus_released); - dev_info(tbn->dev, - "%s: gpios(aoc2ap: %d ap2aoc: %d), mode %d\n", - __func__, tbn->aoc2ap_gpio, tbn->ap2aoc_gpio, tbn->mode); - - dev_dbg(tbn->dev, "bus negotiator initialized: %pK\n", tbn); + dev_info(tbn->dev, "bus negotiator initialized: %pK, mode: %d\n", tbn, tbn->mode); failed: + if (err) { + devm_kfree(dev, tbn); + tbn_context = NULL; + } + return err; } static int tbn_remove(struct platform_device *pdev) { - struct tbn_context *tbn = dev_get_drvdata(&(pdev->dev)); - - free_irq(tbn->aoc2ap_irq, tbn); - if (gpio_is_valid(tbn->aoc2ap_gpio)) - gpio_free(tbn->aoc2ap_gpio); - if (gpio_is_valid(tbn->aoc2ap_gpio)) - gpio_free(tbn->aoc2ap_gpio); + struct device *dev = &pdev->dev; + struct tbn_context *tbn = dev_get_drvdata(dev); + if (tbn->mode == TBN_MODE_GPIO) { + free_irq(tbn->aoc2ap_irq, tbn); + if (gpio_is_valid(tbn->aoc2ap_gpio)) + gpio_free(tbn->aoc2ap_gpio); + if (gpio_is_valid(tbn->aoc2ap_gpio)) + gpio_free(tbn->aoc2ap_gpio); +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + } else if (tbn->mode == TBN_MODE_AOC_CHANNEL) { + kthread_stop(tbn->aoc_channel_task); +#endif + } return 0; } diff --git a/touch_bus_negotiator.h b/touch_bus_negotiator.h index a4c157e..5697489 100644 --- a/touch_bus_negotiator.h +++ b/touch_bus_negotiator.h @@ -6,14 +6,20 @@ #include <linux/notifier.h> #include <linux/mutex.h> #include <linux/device.h> +#include <linux/cdev.h> +#include <linux/kthread.h> + +#define TBN_DEVICE_NAME "tbn" +#define TBN_CLASS_NAME "tbn" #define TBN_REQUEST_BUS_TIMEOUT_MS 500 #define TBN_RELEASE_BUS_TIMEOUT_MS 500 enum tbn_mode { - TBN_MODE_DISABLED, + TBN_MODE_DISABLED = 0, TBN_MODE_GPIO, - TBN_MODE_MAILBOX, + TBN_MODE_AOC_CHANNEL, + TBN_MODE_MOCK, }; enum tbn_bus_owner { @@ -21,22 +27,49 @@ enum tbn_bus_owner { TBN_BUS_OWNER_AOC = 1, }; +enum TbnOperation : __u32 { + TBN_OPERATION_IDLE = 0, + TBN_OPERATION_AP_RELEASE_BUS, + TBN_OPERATION_AP_REQUEST_BUS, +}; + +struct TbnEvent { + __u32 id; + enum TbnOperation operation; +} __packed; + +struct TbnEventResponse { + __u32 id; + __s32 err; + enum TbnOperation operation; + bool lptw_triggered; +} __packed; + struct tbn_context { struct device *dev; struct completion bus_requested; struct completion bus_released; struct mutex dev_mask_mutex; - u8 mode; + u32 mode; u32 max_devices; u32 registered_mask; u32 requested_dev_mask; int aoc2ap_gpio; int ap2aoc_gpio; int aoc2ap_irq; + struct task_struct *aoc_channel_task; + + /* event management */ + struct TbnEventResponse event_resp; +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TBN_AOC_CHANNEL_MODE) + struct TbnEvent event; + struct mutex event_lock; +#endif }; int register_tbn(u32 *output); void unregister_tbn(u32 *output); +int tbn_request_bus_with_result(u32 dev_mask, bool *lptw_triggered); int tbn_request_bus(u32 dev_mask); int tbn_release_bus(u32 dev_mask); diff --git a/touch_offload.c b/touch_offload.c index 393f247..344b6ae 100644 --- a/touch_offload.c +++ b/touch_offload.c @@ -326,7 +326,7 @@ static int touch_offload_allocate_buffers(struct touch_offload_context *context, if (!(context->config.context_channel_types & mask)) continue; - frame->channel_type[chan] = mask; + frame->channel_type[chan] = (__u32)mask; size = 0; switch (mask) { case CONTEXT_CHANNEL_TYPE_DRIVER_STATUS: @@ -338,7 +338,7 @@ static int touch_offload_allocate_buffers(struct touch_offload_context *context, TOUCH_OFFLOAD_FRAME_SIZE_STYLUS_STATUS; break; default: - pr_err("%s: Invalid channel_type = 0x%08X", + pr_err("%s: Invalid channel_type = 0x%08X\n", __func__, mask); goto invalid_context_channel; } @@ -350,7 +350,7 @@ static int touch_offload_allocate_buffers(struct touch_offload_context *context, chan_header = (struct TouchOffloadChannelHeader *) frame->channel_data[chan]; - chan_header->channel_type = mask; + chan_header->channel_type = (__u32)mask; chan_header->channel_size = size; frame->channel_data_size[chan] = size; frame->header.frame_size += size; @@ -502,7 +502,9 @@ static long touch_offload_ioctl(struct file *file, unsigned int ioctl_num, (configure.config.filter_palm && !context->caps.filter_palm) || (configure.config.auto_reporting && - !context->caps.auto_reporting)) { + !context->caps.auto_reporting) || + (configure.config.coord_filter && + !context->caps.coord_filter)) { pr_err("%s: Invalid configuration enables unsupported features!\n", __func__); err = -EINVAL; @@ -657,8 +659,6 @@ int touch_offload_init(struct touch_offload_context *context) { int ret = 0; - pr_debug("%s\n", __func__); - /* Initialize ioctl interface */ context->file_in_use = false; mutex_init(&context->file_lock); @@ -675,40 +675,53 @@ int touch_offload_init(struct touch_offload_context *context) init_completion(&context->reserve_returned); complete_all(&context->reserve_returned); - if (!context->multiple_panels) - scnprintf(context->device_name, 32, "%s", DEVICE_NAME); + if (!strnlen(context->device_name, sizeof(context->device_name))) + scnprintf(context->device_name, sizeof(context->device_name), "%s", DEVICE_NAME); + + pr_info("%s: %s.\n", __func__, context->device_name); /* Initialize char device */ - context->major_num = register_chrdev(0, context->device_name, - &touch_offload_fops); - if (context->major_num < 0) { + cdev_init(&context->dev, &touch_offload_fops); + + ret = alloc_chrdev_region(&context->dev_num, 0, 1, context->device_name); + if (ret < 0) { pr_err("%s: register_chrdev failed with error = %u\n", - __func__, context->major_num); - return context->major_num; + __func__, ret); + return ret; + } + + ret = cdev_add(&context->dev, context->dev_num, 1); + if (ret < 0) { + pr_err("%s: cdev_add failed with error = %u\n", + __func__, ret); + goto err_cdev_add; } context->cls = class_create(THIS_MODULE, context->device_name); if (IS_ERR(context->cls)) { pr_err("%s: class_create failed with error = %ld.\n", __func__, PTR_ERR(context->cls)); - unregister_chrdev(context->major_num, context->device_name); - return PTR_ERR(context->cls); + ret = PTR_ERR(context->cls); + goto err_class_create; } - context->device = device_create(context->cls, NULL, - MKDEV(context->major_num, 0), NULL, - context->device_name); + context->device = device_create(context->cls, NULL, context->dev_num, + NULL, context->device_name); if (IS_ERR(context->device)) { pr_err("%s: device_create failed with error = %ld.\n", __func__, PTR_ERR(context->device)); - class_destroy(context->cls); - unregister_chrdev(context->major_num, context->device_name); - return PTR_ERR(context->device); + ret = PTR_ERR(context->device); + goto err_device_create; } - cdev_init(&context->dev, &touch_offload_fops); - cdev_add(&context->dev, MKDEV(context->major_num, 0), 1); + return ret; +err_device_create: + class_destroy(context->cls); +err_class_create: + cdev_del(&context->dev); +err_cdev_add: + unregister_chrdev_region(context->dev_num, 1); return ret; } EXPORT_SYMBOL(touch_offload_init); @@ -717,13 +730,13 @@ int touch_offload_cleanup(struct touch_offload_context *context) { pr_debug("%s\n", __func__); - cdev_del(&context->dev); - - device_destroy(context->cls, MKDEV(context->major_num, 0)); + device_destroy(context->cls, context->dev_num); class_destroy(context->cls); - unregister_chrdev(context->major_num, context->device_name); + cdev_del(&context->dev); + + unregister_chrdev_region(context->dev_num, 1); complete_all(&context->reserve_returned); diff --git a/touch_offload.h b/touch_offload.h index 2d97d21..0f9f0b6 100644 --- a/touch_offload.h +++ b/touch_offload.h @@ -36,7 +36,7 @@ struct touch_offload_frame { /* Touch Offload Context * * dev - char device - * major_num - device major number + * dev_num - device number * cls - pointer to class associated class * device - pointer to associated device * file - char device file for ioctl interface @@ -61,13 +61,13 @@ struct touch_offload_frame { struct touch_offload_context { /* ioctl interface */ struct cdev dev; - int major_num; + dev_t dev_num; struct class *cls; struct device *device; struct file file; struct mutex file_lock; bool file_in_use; - bool multiple_panels; + bool multiple_panels; /* TODO(b/201610482): remove this variable later! */ char device_name[32]; /* touch capabilities */ |