diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/Android.mk b/drivers/input/touchscreen/focaltech_0flash_mmi/Android.mk index 3e044ab3bc04..646881d4800f 100644 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/Android.mk +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/Android.mk @@ -7,6 +7,10 @@ else KERNEL_CFLAGS += CONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME=ft8719 endif +ifneq ($(BOARD_USES_DOUBLE_TAP),) + KERNEL_CFLAGS += CONFIG_INPUT_FOCALTECH_0FLASH_MMI_ENABLE_DOUBLE_TAP=y +endif + include $(CLEAR_VARS) LOCAL_MODULE := focaltech_0flash_mmi.ko LOCAL_MODULE_TAGS := optional diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/Kbuild b/drivers/input/touchscreen/focaltech_0flash_mmi/Kbuild index 72176d9d31ab..1be7143ef8c2 100644 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/Kbuild +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/Kbuild @@ -34,3 +34,6 @@ ifneq ($(filter ft8009,$(CONFIG_INPUT_FOCALTECH_0FLASH_MMI_IC_NAME)),) focaltech_0flash_mmi-objs += focaltech_flash_ft8756.o focaltech_0flash_mmi-objs += focaltech_spi_v1_1_1.o endif +ifneq ($(filter m y,$(CONFIG_INPUT_FOCALTECH_0FLASH_MMI_ENABLE_DOUBLE_TAP)),) + EXTRA_CFLAGS += -DFOCALTECH_SENSOR_EN +endif diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_config.h b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_config.h index 7400af8abcef..6474b1b77683 100755 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_config.h +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_config.h @@ -164,7 +164,11 @@ * Gesture function enable * default: disable */ +#ifdef FOCALTECH_SENSOR_EN +#define FTS_GESTURE_EN 1 +#else #define FTS_GESTURE_EN 0 +#endif /* * ESD check & protection diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.c b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.c index 7309e15c0329..2f643938d10e 100755 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.c @@ -1479,6 +1479,11 @@ static int fts_ts_probe_entry(struct fts_ts_data *ts_data) spin_lock_init(&ts_data->irq_lock); mutex_init(&ts_data->report_mutex); mutex_init(&ts_data->bus_lock); +#ifdef FOCALTECH_SENSOR_EN + mutex_init(&ts_data->state_mutex); + //unknown screen state + ts_data->screen_state = SCREEN_UNKNOWN; +#endif /* Init communication interface */ ret = fts_bus_init(ts_data); @@ -1732,13 +1737,23 @@ static int fts_ts_suspend(struct device *dev) int ret = 0; struct fts_ts_data *ts_data = fts_data; +#ifdef FOCALTECH_SENSOR_EN + mutex_lock(&ts_data->state_mutex); +#endif + FTS_FUNC_ENTER(); if (ts_data->suspended) { +#ifdef FOCALTECH_SENSOR_EN + mutex_unlock(&ts_data->state_mutex); +#endif FTS_INFO("Already in suspend state"); return 0; } if (ts_data->fw_loading) { +#ifdef FOCALTECH_SENSOR_EN + mutex_unlock(&ts_data->state_mutex); +#endif FTS_INFO("fw upgrade in process, can't suspend"); return 0; } @@ -1748,12 +1763,23 @@ static int fts_ts_suspend(struct device *dev) #endif #if FTS_GESTURE_EN - if (fts_gesture_suspend(ts_data) == 0) { - /* Enter into gesture mode(suspend) */ - ts_data->suspended = true; - return 0; +#ifdef FOCALTECH_SENSOR_EN + if (ts_data->should_enable_gesture) { +#endif + if (fts_gesture_suspend(ts_data) == 0) { + /* Enter into gesture mode(suspend) */ + ts_data->suspended = true; +#ifdef FOCALTECH_SENSOR_EN + ts_data->screen_state = SCREEN_OFF; + mutex_unlock(&ts_data->state_mutex); + FTS_INFO("Enter gesture suspend mode."); +#endif + return 0; + } +#ifdef FOCALTECH_SENSOR_EN } #endif +#endif /* TP enter sleep mode */ @@ -1776,6 +1802,10 @@ static int fts_ts_suspend(struct device *dev) fts_release_all_finger(); ts_data->suspended = true; FTS_FUNC_EXIT(); +#ifdef FOCALTECH_SENSOR_EN + ts_data->screen_state = SCREEN_OFF; + mutex_unlock(&ts_data->state_mutex); +#endif return 0; } @@ -1783,8 +1813,15 @@ static int fts_ts_resume(struct device *dev) { struct fts_ts_data *ts_data = fts_data; +#ifdef FOCALTECH_SENSOR_EN + mutex_lock(&ts_data->state_mutex); +#endif + FTS_FUNC_ENTER(); if (!ts_data->suspended) { +#ifdef FOCALTECH_SENSOR_EN + mutex_unlock(&ts_data->state_mutex); +#endif FTS_DEBUG("Already in awake state"); return 0; } @@ -1805,10 +1842,22 @@ static int fts_ts_resume(struct device *dev) #endif #if FTS_GESTURE_EN - if (fts_gesture_resume(ts_data) == 0) { - ts_data->suspended = false; - return 0; + +#ifdef FOCALTECH_SENSOR_EN + if (ts_data->should_enable_gesture) { +#endif + if (fts_gesture_resume(ts_data) == 0) { + ts_data->suspended = false; +#ifdef FOCALTECH_SENSOR_EN + ts_data->screen_state = SCREEN_ON; + mutex_unlock(&ts_data->state_mutex); + FTS_INFO("Exit from gesture suspend mode."); +#endif + return 0; + } +#ifdef FOCALTECH_SENSOR_EN } +#endif #endif ts_data->suspended = false; @@ -1818,6 +1867,10 @@ static int fts_ts_resume(struct device *dev) #endif FTS_FUNC_EXIT(); +#ifdef FOCALTECH_SENSOR_EN + mutex_unlock(&ts_data->state_mutex); + ts_data->screen_state = SCREEN_ON; +#endif return 0; } diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.h b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.h index 5db82b16a2d2..0e28fc93cf21 100755 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.h +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_core.h @@ -65,6 +65,9 @@ #ifdef FTS_USB_DETECT_EN #include #endif +#ifdef FOCALTECH_SENSOR_EN +#include +#endif /***************************************************************************** * Private constant and macro definitions using #define @@ -111,6 +114,14 @@ /***************************************************************************** * Private enumerations, structures and unions using typedef *****************************************************************************/ +#ifdef FOCALTECH_SENSOR_EN +/* display state */ +enum display_state { + SCREEN_UNKNOWN, + SCREEN_OFF, + SCREEN_ON, +}; +#endif struct ftxxxx_proc { struct proc_dir_entry *proc_entry; u8 opmode; @@ -145,6 +156,16 @@ struct ts_event { int area; }; +#ifdef FOCALTECH_SENSOR_EN +struct focaltech_sensor_platform_data { + struct input_dev *input_sensor_dev; + struct sensors_classdev ps_cdev; + int sensor_opened; + char sensor_data; /* 0 near, 1 far */ + struct fts_ts_data *data; +}; +#endif + struct fts_ts_data { struct i2c_client *client; struct spi_device *spi; @@ -203,6 +224,13 @@ struct fts_ts_data { struct notifier_block charger_notif; #endif +#ifdef FOCALTECH_SENSOR_EN + bool wakeable; + bool should_enable_gesture; + enum display_state screen_state; + struct mutex state_mutex; + struct focaltech_sensor_platform_data *sensor_pdata; +#endif }; /***************************************************************************** diff --git a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_gesture.c b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_gesture.c index edeaf9833d8f..5481f775fd93 100755 --- a/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_gesture.c +++ b/drivers/input/touchscreen/focaltech_0flash_mmi/focaltech_gesture.c @@ -67,6 +67,10 @@ #define GESTURE_Z 0x41 #define GESTURE_C 0x34 +#ifdef FOCALTECH_SENSOR_EN +#define REPORT_MAX_COUNT 10000 +#endif + /***************************************************************************** * Private enumerations, structures and unions using typedef *****************************************************************************/ @@ -93,6 +97,30 @@ struct fts_gesture_st { * Static variables *****************************************************************************/ static struct fts_gesture_st fts_gesture_data; +#ifdef FOCALTECH_SENSOR_EN +#ifdef CONFIG_HAS_WAKELOCK +static struct wake_lock gesture_wakelock; +#else +static struct wakeup_source gesture_wakelock; +#endif +static struct sensors_classdev __maybe_unused sensors_touch_cdev = { + .name = "dt-gesture", + .vendor = "Focaltech", + .version = 1, + .type = SENSOR_TYPE_MOTO_DOUBLE_TAP, + .max_range = "5.0", + .resolution = "5.0", + .sensor_power = "1", + .min_delay = -1, + .max_delay = 0, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +#endif /***************************************************************************** * Global variable or extern global variabls/functions @@ -211,6 +239,9 @@ int fts_create_gesture_sysfs(struct device *dev) static void fts_gesture_report(struct input_dev *input_dev, int gesture_id) { int gesture; +#ifdef FOCALTECH_SENSOR_EN + static int report_cnt = 0; +#endif FTS_DEBUG("gesture_id:0x%x", gesture_id); switch (gesture_id) { @@ -263,13 +294,134 @@ static void fts_gesture_report(struct input_dev *input_dev, int gesture_id) /* report event key */ if (gesture != -1) { FTS_DEBUG("Gesture Code=%d", gesture); +#ifdef FOCALTECH_SENSOR_EN + if (!fts_data->wakeable) { + FTS_INFO("Predict enable failed."); + fts_data->should_enable_gesture = false; + fts_gesture_resume(fts_data); + return; + } + input_report_abs(fts_data->sensor_pdata->input_sensor_dev, + ABS_DISTANCE, ++report_cnt); + FTS_INFO("input report: %d", report_cnt); + if (report_cnt >= REPORT_MAX_COUNT) + report_cnt = 0; + input_sync(fts_data->sensor_pdata->input_sensor_dev); +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_timeout(&gesture_wakelock, msecs_to_jiffies(5000)); +#else + __pm_wakeup_event(&gesture_wakelock, msecs_to_jiffies(5000)); +#endif +#else input_report_key(input_dev, gesture, 1); input_sync(input_dev); input_report_key(input_dev, gesture, 0); input_sync(input_dev); +#endif } } +#ifdef FOCALTECH_SENSOR_EN +static int fts_sensor_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + FTS_INFO("Gesture set enable %d!", enable); + mutex_lock(&fts_data->state_mutex); + if (enable == 1) { + fts_data->wakeable = true; + if (!fts_data->suspended && fts_data->screen_state == SCREEN_ON) { + FTS_INFO("Touch still in normal mode, skip to set to gesture mode"); + mutex_unlock(&fts_data->state_mutex); + return 0; + } + if (fts_gesture_data.active == ENABLE) { + FTS_INFO("already in gesture mode"); + mutex_unlock(&fts_data->state_mutex); + return 0; + } + + fts_data->should_enable_gesture = true; + fts_gesture_suspend(fts_data); + FTS_INFO("Set IC in doze mode"); + } else if (enable == 0) { + fts_data->wakeable = false; + //fts_gesture_resume(fts_data); + } else { + FTS_INFO("unknown enable symbol\n"); + } + mutex_unlock(&fts_data->state_mutex); + return 0; +} + +static int fts_sensor_init(struct fts_ts_data *data) +{ + struct focaltech_sensor_platform_data *sensor_pdata; + struct input_dev *sensor_input_dev; + int err; + + sensor_input_dev = input_allocate_device(); + if (!sensor_input_dev) { + FTS_ERROR("Failed to allocate device"); + goto exit; + } + + sensor_pdata = devm_kzalloc(&sensor_input_dev->dev, + sizeof(struct focaltech_sensor_platform_data), + GFP_KERNEL); + if (!sensor_pdata) { + FTS_ERROR("Failed to allocate memory"); + goto free_sensor_pdata; + } + data->sensor_pdata = sensor_pdata; + + __set_bit(EV_ABS, sensor_input_dev->evbit); + __set_bit(EV_SYN, sensor_input_dev->evbit); + input_set_abs_params(sensor_input_dev, ABS_DISTANCE, + 0, REPORT_MAX_COUNT, 0, 0); + sensor_input_dev->name = "double-tap"; + data->sensor_pdata->input_sensor_dev = sensor_input_dev; + + err = input_register_device(sensor_input_dev); + if (err) { + FTS_ERROR("Unable to register device, err=%d", err); + goto free_sensor_input_dev; + } + + sensor_pdata->ps_cdev = sensors_touch_cdev; + sensor_pdata->ps_cdev.sensors_enable = fts_sensor_set_enable; + sensor_pdata->data = data; + + err = sensors_classdev_register(&sensor_input_dev->dev, + &sensor_pdata->ps_cdev); + if (err) + goto unregister_sensor_input_device; + + return 0; + +unregister_sensor_input_device: + input_unregister_device(data->sensor_pdata->input_sensor_dev); +free_sensor_input_dev: + input_free_device(data->sensor_pdata->input_sensor_dev); +free_sensor_pdata: + devm_kfree(&sensor_input_dev->dev, sensor_pdata); + data->sensor_pdata = NULL; +exit: + return 1; +} + +int fts_sensor_remove(struct fts_ts_data *data) +{ + sensors_classdev_unregister(&data->sensor_pdata->ps_cdev); + input_unregister_device(data->sensor_pdata->input_sensor_dev); + devm_kfree(&data->sensor_pdata->input_sensor_dev->dev, + data->sensor_pdata); + data->sensor_pdata = NULL; + data->wakeable = false; + data->should_enable_gesture = false; + return 0; +} +#endif + /***************************************************************************** * Name: fts_gesture_readdata * Brief: Read information about gesture: enable flag/gesture points..., if ges- @@ -433,6 +585,9 @@ int fts_gesture_resume(struct fts_ts_data *ts_data) int fts_gesture_init(struct fts_ts_data *ts_data) { struct input_dev *input_dev = ts_data->input_dev; +#ifdef FOCALTECH_SENSOR_EN + static bool initialized_sensor; +#endif FTS_FUNC_ENTER(); input_set_capability(input_dev, EV_KEY, KEY_POWER); @@ -466,6 +621,18 @@ int fts_gesture_init(struct fts_ts_data *ts_data) __set_bit(KEY_GESTURE_C, input_dev->keybit); __set_bit(KEY_GESTURE_Z, input_dev->keybit); +#ifdef FOCALTECH_SENSOR_EN + if (!initialized_sensor) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&gesture_wakelock, WAKE_LOCK_SUSPEND, "poll-wake-lock"); +#else + wakeup_source_init(&gesture_wakelock, "ets_wake_lock"); +#endif + if (!fts_sensor_init(ts_data)) + initialized_sensor = true; + } +#endif + fts_create_gesture_sysfs(ts_data->dev); memset(&fts_gesture_data, 0, sizeof(struct fts_gesture_st));