diff options
author | Wendly Li <wendlyli@google.com> | 2022-07-07 07:49:17 +0000 |
---|---|---|
committer | Wendly Li <wendlyli@google.com> | 2022-07-21 05:30:40 +0000 |
commit | e788d534c077d25514338001eae58ce4918649bc (patch) | |
tree | 0e92ed76e0645d6a52bd7da8d486edaba5ed05f2 /goodix_ts_core.c | |
parent | 178ef0cefe5c2e2bc636a00fad7250cb69438ad5 (diff) | |
download | goodix_touch-e788d534c077d25514338001eae58ce4918649bc.tar.gz |
touch/goodix: Support finger leaves event for UDFPS.
Bug: 214118944
Bug: 239381635
Test: LHBM is off right after LPTW finger leaves.
Change-Id: I95615fc8b75d15db41765d9320aa68d9d016e1a2
Signed-off-by: Wendly Li <wendlyli@google.com>
Diffstat (limited to 'goodix_ts_core.c')
-rw-r--r-- | goodix_ts_core.c | 185 |
1 files changed, 172 insertions, 13 deletions
diff --git a/goodix_ts_core.c b/goodix_ts_core.c index da5bc98..3cfe0bf 100644 --- a/goodix_ts_core.c +++ b/goodix_ts_core.c @@ -808,7 +808,7 @@ int hardware_reset(struct device *dev) int set_scan_mode(struct device *dev, enum scan_mode mode) { struct goodix_ts_core *cd = dev_get_drvdata(dev); - return cd->hw_ops->set_scan_mode(cd, mode); + return cd->hw_ops->set_scan_mode(cd, (enum raw_scan_mode)mode); } int set_sensing_enabled(struct device *dev, bool enabled) @@ -969,6 +969,13 @@ static int get_screen_protector_mode( return 0; } +static int set_heatmap_enabled( + void *private_data, struct gti_heatmap_cmd *cmd) +{ + struct goodix_ts_core *cd = private_data; + return cd->hw_ops->set_heatmap_enabled(cd, cmd->setting == GTI_HEATMAP_ENABLE); +} + #endif /* prosfs create */ @@ -1155,7 +1162,6 @@ static int goodix_parse_dt_resolution( ts_err("failed get panel-max-p, use default"); board_data->panel_max_p = GOODIX_PEN_MAX_PRESSURE; } - return 0; } @@ -1276,6 +1282,18 @@ static int goodix_parse_dt( return r; } + r = of_property_read_u32(node, "goodix,udfps-x", &board_data->udfps_x); + if (r) { + ts_err("failed to get udfps-x"); + return r; + } + + r = of_property_read_u32(node, "goodix,udfps-y", &board_data->udfps_y); + if (r) { + ts_err("failed to get udfps-y"); + return r; + } + /* get sleep mode flag */ board_data->sleep_enable = of_property_read_bool(node, "goodix,sleep-enable"); @@ -1436,6 +1454,50 @@ static void goodix_ts_report_finger_goog( } #endif +static void goodix_ts_report_gesture_up(struct goodix_ts_core *cd) +{ + struct input_dev *dev = cd->input_dev; + + ts_info("goodix_ts_report_gesture_up"); + + mutex_lock(&dev->mutex); + + input_set_timestamp(dev, cd->coords_timestamp); + + /* Finger down on UDFPS area. */ + input_mt_slot(dev, 0); + input_report_key(dev, BTN_TOUCH, 1); + input_mt_report_slot_state(dev, MT_TOOL_FINGER, 1); + input_report_abs(dev, ABS_MT_POSITION_X, cd->board_data.udfps_x); + input_report_abs(dev, ABS_MT_POSITION_Y, cd->board_data.udfps_y); + input_report_abs(dev, ABS_MT_TOUCH_MAJOR, 200); + input_report_abs(dev, ABS_MT_TOUCH_MINOR, 200); +#ifndef SKIP_PRESSURE + input_report_abs(dev, ABS_MT_PRESSURE, 1); +#endif + /*input_report_abs(dev, ABS_MT_ORIENTATION, + ts_data->fts_gesture_data.orientation[0]);*/ + input_sync(dev); + + /* Report MT_TOOL_PALM for canceling the touch event. */ + input_mt_slot(dev, 0); + input_report_key(dev, BTN_TOUCH, 1); + input_mt_report_slot_state(dev, MT_TOOL_PALM, 1); + input_sync(dev); + + /* Release touches. */ + input_mt_slot(dev, 0); +#ifndef SKIP_PRESSURE + input_report_abs(dev, ABS_MT_PRESSURE, 0); +#endif + input_mt_report_slot_state(dev, MT_TOOL_FINGER, 0); + input_report_abs(dev, ABS_MT_TRACKING_ID, -1); + input_report_key(dev, BTN_TOUCH, 0); + input_sync(dev); + + mutex_unlock(&dev->mutex); +} + static int goodix_ts_request_handle( struct goodix_ts_core *cd, struct goodix_ts_event *ts_event) { @@ -1466,13 +1528,15 @@ static irqreturn_t goodix_ts_isr(int irq, void *data) return IRQ_WAKE_THREAD; } -void goodix_ts_report_status(struct goodix_ts_event *ts_event) +void goodix_ts_report_status(struct goodix_ts_core *core_data, + struct goodix_ts_event *ts_event) { struct goodix_status_data *st = &ts_event->status_data; int i; u8 checksum = 0; int len = sizeof(ts_event->status_data); u8 *data = (u8 *)st; + struct gti_fw_status_data status_data = { 0 }; for (i = 0; i < len - 1; i++) checksum += data[i]; @@ -1489,6 +1553,28 @@ void goodix_ts_report_status(struct goodix_ts_event *ts_event) st->water_sta, st->before_factorA, st->after_factorA, st->base_update_type, st->soft_reset_type, st->palm_sta, st->noise_lv, st->grip_type); + + if (st->soft_reset) + goog_notify_fw_status_changed(core_data->gti, GTI_FW_STATUE_RESET, + &status_data); + + if (st->palm_change) { + goog_notify_fw_status_changed(core_data->gti, + st->palm_sta ? GTI_FW_STATUE_PALM_ENTER : GTI_FW_STATUE_PALM_EXIT, + &status_data); + } + + if (st->grip_change) { + goog_notify_fw_status_changed(core_data->gti, + st->grip_type ? GTI_FW_STATUE_GRIP_ENTER : GTI_FW_STATUE_GRIP_EXIT, + &status_data); + } + + if (st->noise_lv_change) { + status_data.noise_level = st->noise_lv; + goog_notify_fw_status_changed(core_data->gti, GTI_FW_STATUE_NOISE_MODE, + &status_data); + } } /** @@ -1547,6 +1633,9 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) core_data, &ts_event->touch_data); #endif } + if (ts_event->event_type & EVENT_GESTURE) { + core_data->coords_timestamp = core_data->isr_timestamp; + } if (core_data->board_data.pen_enable && ts_event->event_type & EVENT_PEN) { goodix_ts_report_pen( @@ -1555,7 +1644,7 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) if (ts_event->event_type & EVENT_REQUEST) goodix_ts_request_handle(core_data, ts_event); if (ts_event->event_type & EVENT_STATUS) - goodix_ts_report_status(ts_event); + goodix_ts_report_status(core_data, ts_event); /* read done */ hw_ops->after_event_handler(core_data); @@ -1813,6 +1902,8 @@ static int goodix_ts_input_dev_config(struct goodix_ts_core *core_data) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_MT_ORIENTATION, -4096, 4096, 0, 0); + input_set_abs_params( + input_dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER, MT_TOOL_PALM, 0, 0); #ifdef INPUT_TYPE_B_PROTOCOL #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0) input_mt_init_slots(input_dev, GOODIX_MAX_TOUCH, INPUT_MT_DIRECT); @@ -2103,7 +2194,6 @@ static int goodix_ts_suspend(struct goodix_ts_core *core_data) atomic_set(&core_data->suspended, 1); /* disable irq */ hw_ops->irq_enable(core_data, false); - hw_ops->set_heatmap_enabled(core_data, false); /* * notify suspend event, inform the esd protector @@ -2172,6 +2262,50 @@ out: return 0; } +static bool check_gesture_mode(struct goodix_ts_core *core_data) +{ + enum raw_scan_mode scan_mode = RAW_SCAN_MODE_AUTO; + int err = 0; + + err = core_data->hw_ops->get_scan_mode(core_data, &scan_mode); + if (err != 0) { + return false; + } + return (scan_mode == RAW_SCAN_MODE_LOW_POWER_ACTIVE) || + (scan_mode == RAW_SCAN_MODE_LOW_POWER_IDLE); +} + +static void monitor_gesture_event(struct work_struct *work) +{ + struct delayed_work *delayed_work = container_of( + work, struct delayed_work, work); + struct goodix_ts_core *cd = container_of(delayed_work, struct goodix_ts_core, + monitor_gesture_work); + struct goodix_gesture_data* gesture_data = &cd->ts_event.gesture_data; + + if (gesture_data->gesture_type == GOODIX_GESTURE_UNKNOWN) { + if (ktime_get() < cd->gesture_down_timeout) { + queue_delayed_work(cd->event_wq, &cd->monitor_gesture_work, + msecs_to_jiffies(5)); + return; + } + } else if (gesture_data->gesture_type == GOODIX_GESTURE_FOD_DOWN) { + if (ktime_get() < cd->gesture_up_timeout) { + queue_delayed_work(cd->event_wq, &cd->monitor_gesture_work, + msecs_to_jiffies(5)); + return; + } + } + + goodix_ts_report_gesture_up(cd); + + /* reset device or power on*/ + if (cd->board_data.sleep_enable) + cd->hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS); + else + goodix_ts_power_on(cd); +} + /** * goodix_ts_resume - Touchscreen resume function * Called by PM/FB/EARLYSUSPEN module to wakeup device @@ -2180,6 +2314,7 @@ static int goodix_ts_resume(struct goodix_ts_core *core_data) { struct goodix_ext_module *ext_module, *next; struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; + struct goodix_gesture_data* gesture_data = &core_data->ts_event.gesture_data; int ret; if (core_data->init_stage < CORE_INIT_STAGE2 || @@ -2212,11 +2347,19 @@ static int goodix_ts_resume(struct goodix_ts_core *core_data) } mutex_unlock(&goodix_modules.mutex); - /* reset device or power on*/ - if (core_data->board_data.sleep_enable) - hw_ops->reset(core_data, GOODIX_NORMAL_RESET_DELAY_MS); - else - goodix_ts_power_on(core_data); + if (check_gesture_mode(core_data)) { + gesture_data->gesture_type = GOODIX_GESTURE_UNKNOWN; + core_data->gesture_down_timeout = ktime_add_ms(ktime_get(), 100); + core_data->gesture_up_timeout = ktime_add_ms(ktime_get(), 500); + queue_delayed_work(core_data->event_wq, &core_data->monitor_gesture_work, + msecs_to_jiffies(5)); + } else { + /* reset device or power on*/ + if (core_data->board_data.sleep_enable) + hw_ops->reset(core_data, GOODIX_NORMAL_RESET_DELAY_MS); + else + goodix_ts_power_on(core_data); + } mutex_lock(&goodix_modules.mutex); if (!list_empty(&goodix_modules.head)) { @@ -2238,8 +2381,6 @@ static int goodix_ts_resume(struct goodix_ts_core *core_data) } mutex_unlock(&goodix_modules.mutex); - hw_ops->set_heatmap_enabled(core_data, true); - out: /* enable irq */ hw_ops->irq_enable(core_data, true); @@ -2406,6 +2547,15 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) goto err_init_apis; } + cd->event_wq = alloc_workqueue("goodix_wq", WQ_UNBOUND | + WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); + if (!cd->event_wq) { + ts_err("Cannot create work thread\n"); + ret = -ENOMEM; + goto err_alloc_workqueue; + } + INIT_DELAYED_WORK(&cd->monitor_gesture_work, monitor_gesture_event); + #if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) options = devm_kzalloc(&cd->pdev->dev, sizeof(struct gti_optional_configuration), GFP_KERNEL); @@ -2418,6 +2568,7 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) options->get_palm_mode = get_palm_mode; options->set_screen_protector_mode = set_screen_protector_mode; options->get_screen_protector_mode = get_screen_protector_mode; + options->set_heatmap_enabled = set_heatmap_enabled; cd->gti = goog_touch_interface_probe( cd, cd->bus->dev, cd->input_dev, gti_default_handler, options); @@ -2445,12 +2596,14 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) goto err_init_esd; } +#if IS_ENABLED(CONFIG_GOODIX_GESTURE) /* gesture init */ ret = gesture_module_init(); if (ret < 0) { ts_err("failed set init gesture"); goto err_init_gesture; } +#endif /* inspect init */ ret = inspect_module_init(); @@ -2465,7 +2618,6 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) cd->mutual_data = devm_kzalloc(&cd->pdev->dev, mutual_size, GFP_KERNEL); cd->self_sensing_data = devm_kzalloc(&cd->pdev->dev, self_sensing_size, GFP_KERNEL); - cd->hw_ops->set_heatmap_enabled(cd, true); /* request irq line */ ret = goodix_ts_irq_setup(cd); @@ -2480,8 +2632,10 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) err_setup_irq: inspect_module_exit(); err_init_inspect: +#if IS_ENABLED(CONFIG_GOODIX_GESTURE) gesture_module_exit(); err_init_gesture: +#endif goodix_ts_esd_uninit(cd); err_init_esd: goodix_ts_procfs_exit(cd); @@ -2490,6 +2644,8 @@ err_init_procfs: goog_pm_unregister_notification(cd->gti); err_init_tpm: #endif + destroy_workqueue(cd->event_wq); +err_alloc_workqueue: touch_apis_deinit(&cd->pdev->dev); err_init_apis: goodix_ts_sysfs_exit(cd); @@ -2780,7 +2936,9 @@ static int goodix_ts_remove(struct platform_device *pdev) goodix_set_pinctrl_state(core_data, PINCTRL_MODE_SUSPEND); if (core_data->init_stage >= CORE_INIT_STAGE2) { +#if IS_ENABLED(CONFIG_GOODIX_GESTURE) gesture_module_exit(); +#endif inspect_module_exit(); hw_ops->irq_enable(core_data, false); #if IS_ENABLED(CONFIG_FB) @@ -2800,6 +2958,7 @@ static int goodix_ts_remove(struct platform_device *pdev) #endif goog_touch_interface_remove(core_data->gti); #endif + destroy_workqueue(core_data->event_wq); touch_apis_deinit(&core_data->pdev->dev); goodix_ts_procfs_exit(core_data); goodix_ts_power_off(core_data); |