diff options
author | Wendly Li <wendlyli@google.com> | 2022-09-26 07:32:45 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2022-12-22 02:54:32 +0000 |
commit | 60af8f12336967a3684faca2c9dd06d03177da69 (patch) | |
tree | f9e7cf7f377fcc502ec5adbb7499d20ab0b32750 | |
parent | e5b0ac0a985b17dc4865532b84daa92d1fc09798 (diff) | |
download | common-60af8f12336967a3684faca2c9dd06d03177da69.tar.gz |
touch/common: suppport aoc cannel mode for tbn
Bug: 177329320
Test: Wakeup gesture works properly
Change-Id: I233c4c89a985b9279a0833c734c834a262eabe22
Signed-off-by: Wendly Li <wendlyli@google.com>
-rw-r--r-- | Kbuild | 1 | ||||
-rw-r--r-- | Kconfig | 8 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | goog_touch_interface.c | 12 | ||||
-rw-r--r-- | goog_touch_interface.h | 4 | ||||
-rw-r--r-- | touch_bus_negotiator.c | 239 | ||||
-rw-r--r-- | touch_bus_negotiator.h | 38 |
7 files changed, 267 insertions, 36 deletions
@@ -3,6 +3,7 @@ ccflags-y += -I$(srctree)/$(src)/include ccflags-y += -I$(srctree)/../private/google-modules/display ccflags-y += -I$(srctree)/../private/google-modules/display/include/uapi +ccflags-y += -I$(srctree)/../private/google-modules/aoc obj-$(CONFIG_TOUCHSCREEN_TBN) += touch_bus_negotiator.o obj-$(CONFIG_TOUCHSCREEN_HEATMAP) += heatmap.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) @@ -4,6 +4,7 @@ KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build M ?= $(shell pwd) EXTRA_CFLAGS += -DDYNAMIC_DEBUG_MODULE +EXTRA_SYMBOLS += $(OUT_DIR)/../private/google-modules/aoc/Module.symvers include $(KERNEL_SRC)/../private/google-modules/soc/gs/Makefile.include diff --git a/goog_touch_interface.c b/goog_touch_interface.c index dd0de7e..cd1f8fd 100644 --- a/goog_touch_interface.c +++ b/goog_touch_interface.c @@ -2904,7 +2904,8 @@ static void goog_pm_resume(struct gti_pm *pm) 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); } @@ -3177,6 +3178,15 @@ init_variable_report_rate_failed: 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; diff --git a/goog_touch_interface.h b/goog_touch_interface.h index bb33686..35357b6 100644 --- a/goog_touch_interface.h +++ b/goog_touch_interface.h @@ -549,6 +549,7 @@ struct gti_pm { * @ignore_palm_update: Ignore fw_palm status updates made on offload state change. * @default_palm_enabled: the palm default setting. * @wakeup_before_force_active_enabled: waking up the screen to force active. + * @lptw_triggered: LPTW is triggered or not. * @wakeup_before_force_active_delay: the ms delay after waking up screen to force active. * @offload_id: id that used by touch offload. * @heatmap_buf: heatmap buffer that used by v4l2. @@ -617,6 +618,7 @@ struct goog_touch_interface { bool ignore_palm_update; bool default_palm_enabled; bool wakeup_before_force_active_enabled; + bool lptw_triggered; unsigned int wakeup_before_force_active_delay; union { u8 offload_id_byte[4]; @@ -710,5 +712,7 @@ void goog_notify_fw_status_changed(struct goog_touch_interface *gti, 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/touch_bus_negotiator.c b/touch_bus_negotiator.c index cae8435..31d96b1 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,108 @@ 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; + + while (!kthread_should_stop()) { + if (!aoc_tbn_service_ready()) { + dev_warn(tbn->dev, "%s: AOC TBN service is not ready.\n", + __func__); + 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,21 +181,27 @@ 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); @@ -117,12 +230,34 @@ int tbn_handshaking(struct tbn_context *tbn, enum tbn_operation operation) } 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; + + 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 { + 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; @@ -139,11 +274,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; @@ -151,6 +288,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) @@ -179,7 +322,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", @@ -238,22 +381,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")) { - tbn->mode = TBN_MODE_GPIO; + err = of_property_read_u32(np, "tbn,mode", &tbn->mode); + if (err) + tbn->mode = TBN_MODE_DISABLED; + 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, @@ -292,8 +443,30 @@ static int tbn_probe(struct platform_device *pdev) __func__, tbn->aoc2ap_gpio); 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 { - 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); @@ -303,11 +476,7 @@ 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: return err; @@ -315,14 +484,20 @@ failed: 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..a7c971f 100644 --- a/touch_bus_negotiator.h +++ b/touch_bus_negotiator.h @@ -6,14 +6,19 @@ #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, }; enum tbn_bus_owner { @@ -21,22 +26,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); |