diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/Android.mk b/drivers/input/touchscreen/ilitek_0flash_mmi/Android.mk index be2343fa6391..9b2dfe8ae350 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/Android.mk +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/Android.mk @@ -1,6 +1,14 @@ DLKM_DIR := motorola/kernel/modules LOCAL_PATH := $(call my-dir) +ifneq ($(BOARD_USES_DOUBLE_TAP),) + KERNEL_CFLAGS += CONFIG_INPUT_ILI_0FLASH_MMI_ENABLE_DOUBLE_TAP=y +endif + +ifneq ($(BOARD_USES_PANEL_NOTIFICATIONS),) + KERNEL_CFLAGS += CONFIG_INPUT_ILI_PANEL_NOTIFICATIONS=y +endif + include $(CLEAR_VARS) LOCAL_MODULE := ilitek_0flash_mmi.ko LOCAL_MODULE_TAGS := optional diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/Kbuild b/drivers/input/touchscreen/ilitek_0flash_mmi/Kbuild index 382156b186fe..15cfc7114d5a 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/Kbuild +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/Kbuild @@ -7,6 +7,13 @@ ifeq ($(filter m y, $(CONFIG_TOUCHSCREEN_ILITEK_CHIPSET)),) obj-m += ilitek_0flash_mmi.o endif +ifneq ($(filter m y,$(CONFIG_INPUT_ILI_0FLASH_MMI_ENABLE_DOUBLE_TAP)),) + EXTRA_CFLAGS += -DILI_SENSOR_EN +endif +ifneq ($(filter m y,$(CONFIG_INPUT_ILI_PANEL_NOTIFICATIONS)),) +EXTRA_CFLAGS += -DILI_CONFIG_PANEL_NOTIFICATIONS +endif + ilitek_0flash_mmi-objs += ilitek.o ilitek_0flash_mmi-objs += ilitek_spi.o ilitek_0flash_mmi-objs += ilitek_qcom.o diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.c b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.c index 58fbc2519bce..2cf15603baaa 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.c +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.c @@ -407,6 +407,18 @@ int ili_sleep_handler(int mode) ILI_ERR("Check busy timeout during suspend\n"); } +#ifdef ILI_SENSOR_EN + if (ilits->should_enable_gesture) { + ili_switch_tp_mode(P5_X_FW_GESTURE_MODE); + enable_irq_wake(ilits->irq_num); + ili_irq_enable(); + ilits->wakeable = true; + } else { + if (ili_ic_func_ctrl("sleep", SLEEP_IN) < 0) + ILI_ERR("Write sleep in cmd failed\n"); + ilits->wakeable = false; + } +#else if (ilits->gesture) { ili_switch_tp_mode(P5_X_FW_GESTURE_MODE); enable_irq_wake(ilits->irq_num); @@ -415,6 +427,7 @@ int ili_sleep_handler(int mode) if (ili_ic_func_ctrl("sleep", SLEEP_IN) < 0) ILI_ERR("Write sleep in cmd failed\n"); } +#endif ILI_INFO("TP suspend end\n"); ilits->tp_suspend = true; break; @@ -458,6 +471,13 @@ int ili_sleep_handler(int mode) ili_wq_ctrl(WQ_ESD, ENABLE); ili_wq_ctrl(WQ_BAT, ENABLE); ilits->tp_suspend = false; +#ifdef ILI_SENSOR_EN + if (ilits->wakeable) { + disable_irq_wake(ilits->irq_num); + ilits->gesture_enabled = false; + ilits->wakeable = false; + } +#endif ILI_INFO("TP resume end\n"); #endif ili_irq_enable(); diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.h b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.h index 55a1977e9da2..e391df53e923 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.h +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek.h @@ -106,6 +106,13 @@ #include #endif +#ifdef ILI_SENSOR_EN +#include +#endif +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS +#include +#endif + #define DRIVER_VERSION "3.0.2.0.200512" /* Options */ @@ -128,7 +135,11 @@ #define MT_PRESSURE DISABLE #define ENABLE_WQ_ESD DISABLE #define ENABLE_WQ_BAT DISABLE +#ifdef ILI_SENSOR_EN +#define ENABLE_GESTURE ENABLE +#else #define ENABLE_GESTURE DISABLE +#endif #define REGULATOR_POWER DISABLE #define TP_SUSPEND_PRIO ENABLE #define RESUME_BY_DDI DISABLE @@ -732,6 +743,23 @@ struct gesture_symbol { #define TDDI_CHIP_RESET_ADDR 0x40050 #define RAWDATA_NO_BK_SHIFT 8192 +#ifdef ILI_SENSOR_EN +/* display state */ +enum display_state { + SCREEN_UNKNOWN, + SCREEN_OFF, + SCREEN_ON, +}; +struct ili_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 ilitek_ts_data *data; +}; +#define REPORT_MAX_COUNT 10000 +#endif + struct ilitek_ts_data { struct i2c_client *i2c; struct spi_device *spi; @@ -752,6 +780,10 @@ struct ilitek_ts_data { struct early_suspend early_suspend; #endif +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS + struct notifier_block panel_notif; +#endif + struct mutex touch_mutex; struct mutex debug_mutex; struct mutex debug_read_mutex; @@ -870,6 +902,21 @@ struct ilitek_ts_data { atomic_t cmd_int_check; atomic_t esd_stat; +#ifdef ILI_SENSOR_EN + bool wakeable; + bool should_enable_gesture; + bool gesture_enabled; + uint32_t report_gesture_key; + enum display_state screen_state; + struct mutex state_mutex; + struct ili_sensor_platform_data *sensor_pdata; +#ifdef CONFIG_HAS_WAKELOCK + struct wake_lock gesture_wakelock; +#else + struct wakeup_source gesture_wakelock; +#endif +#endif + /* Event for driver test */ struct completion esd_done; diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_qcom.c b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_qcom.c index 658a521289e1..b6c5f8ba2340 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_qcom.c +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_qcom.c @@ -22,6 +22,45 @@ #include "ilitek.h" +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS +#define register_panel_notifier panel_register_notifier +#define unregister_panel_notifier panel_unregister_notifier +enum touch_state { + TOUCH_DEEP_SLEEP_STATE = 0, + TOUCH_LOW_POWER_STATE, +}; +#else +#define register_panel_notifier(...) rc +#define unregister_panel_notifier(...) rc +#endif + +#ifdef ILI_SENSOR_EN +static struct sensors_classdev __maybe_unused sensors_touch_cdev = { + + .name = "dt-gesture", + .vendor = "ilitek", + .version = 1, + .type = SENSOR_TYPE_MOTO_DOUBLE_TAP, + .max_range = "5.0", + .resolution = "5.0", + .sensor_power = "1", + .min_delay = 0, + .max_delay = 0, + /* WAKE_UP & SPECIAL_REPORT */ + .flags = 1 | 6, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; +#endif + +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS +static int ili_panel_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#endif + #define DTS_INT_GPIO "touch,irq-gpio" #define DTS_RESET_GPIO "touch,reset-gpio" #define DTS_OF_NAME "tchip,ilitek" @@ -546,6 +585,135 @@ static void ilitek_plat_late_resume(struct early_suspend *h) } #endif +#ifdef ILI_SENSOR_EN +static int ili_sensor_set_enable(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + ILI_INFO("Gesture set enable %d!", enable); + mutex_lock(&ilits->state_mutex); + if (enable == 1) { + ilits->should_enable_gesture = true; + } else if (enable == 0) { + ilits->should_enable_gesture = false; + } else { + ILI_INFO("unknown enable symbol\n"); + } + mutex_unlock(&ilits->state_mutex); + return 0; +} + +static int ili_sensor_init(struct ilitek_ts_data *data) +{ + struct ili_sensor_platform_data *sensor_pdata; + struct input_dev *sensor_input_dev; + int err; + + sensor_input_dev = input_allocate_device(); + if (!sensor_input_dev) { + ILI_ERR("Failed to allocate device"); + goto exit; + } + + sensor_pdata = devm_kzalloc(&sensor_input_dev->dev, + sizeof(struct ili_sensor_platform_data), + GFP_KERNEL); + if (!sensor_pdata) { + ILI_ERR("Failed to allocate memory"); + goto free_sensor_pdata; + } + data->sensor_pdata = sensor_pdata; + + if (data->report_gesture_key) { + __set_bit(EV_KEY, sensor_input_dev->evbit); + __set_bit(KEY_F1, sensor_input_dev->keybit); + } else { + __set_bit(EV_ABS, sensor_input_dev->evbit); + input_set_abs_params(sensor_input_dev, ABS_DISTANCE, + 0, REPORT_MAX_COUNT, 0, 0); + } + __set_bit(EV_SYN, sensor_input_dev->evbit); + + sensor_input_dev->name = "double-tap"; + data->sensor_pdata->input_sensor_dev = sensor_input_dev; + + err = input_register_device(sensor_input_dev); + if (err) { + ILI_ERR("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 = ili_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 ili_sensor_remove(struct ilitek_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 + +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS +static int ili_panel_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ +#ifdef ILI_SENSOR_EN + struct ilitek_ts_data *ts = + container_of(self, struct ilitek_ts_data, panel_notif); +#endif + + switch (event) { + case PANEL_EVENT_PRE_DISPLAY_OFF: + ILI_INFO("event=%lu\n", event); + if (ili_sleep_handler(TP_SUSPEND) < 0) + ILI_ERR("TP suspend failed\n"); +#ifdef ILI_SENSOR_EN + if (ts->should_enable_gesture) { + ILI_INFO("double tap gesture suspend\n"); + touch_set_state(TOUCH_LOW_POWER_STATE, TOUCH_PANEL_IDX_PRIMARY); + } else { + touch_set_state(TOUCH_DEEP_SLEEP_STATE, TOUCH_PANEL_IDX_PRIMARY); + } +#endif + break; + + case PANEL_EVENT_DISPLAY_ON: + ILI_INFO("event=%lu\n", event); + if (ili_sleep_handler(TP_RESUME) < 0) + ILI_ERR("TP resume failed\n"); + break; + default: /* use DEV_TS here to avoid unused variable */ + ILI_INFO("%s: function not implemented event %lu\n", __func__, event); + break; + } + + return 0; +} +#endif + static void ilitek_plat_sleep_init(void) { int ret; @@ -576,6 +744,13 @@ static void ilitek_plat_sleep_init(void) } #endif #endif/* CONFIG_DRM */ +#ifdef ILI_CONFIG_PANEL_NOTIFICATIONS + ilits->panel_notif.notifier_call = ili_panel_notifier_callback; + ret = register_panel_notifier(&ilits->panel_notif); + if(ret) { + ILI_ERR("register panel_notifier failed. ret=%d\n", ret); + } +#endif #if defined(CONFIG_HAS_EARLYSUSPEND) ILI_ERR("Init eqarly_suspend struct\n"); ilits->early_suspend.suspend = ilitek_plat_early_suspend; @@ -607,6 +782,14 @@ static int ilitek_plat_gpio_register(void) return err; } #endif +#endif +#ifdef ILI_SENSOR_EN + if (of_property_read_bool(dev_node, "ilitek,report_gesture_key")) { + ILI_INFO("ilitek,report_gesture_key set"); + ilits->report_gesture_key = 1; + } else { + ilits->report_gesture_key = 0; + } #endif ilits->tp_int = of_get_named_gpio_flags(dev_node, DTS_INT_GPIO, 0, &flag); ilits->tp_rst = of_get_named_gpio_flags(dev_node, DTS_RESET_GPIO, 0, &flag); @@ -653,6 +836,9 @@ out: static int ilitek_plat_probe(void) { +#ifdef ILI_SENSOR_EN + static bool initialized_sensor; +#endif ILI_INFO("platform probe\n"); #if REGULATOR_POWER @@ -675,6 +861,20 @@ static int ilitek_plat_probe(void) ilitek_plat_sleep_init(); ilits->pm_suspend = false; init_completion(&ilits->pm_completion); +#ifdef ILI_SENSOR_EN + mutex_init(&ilits->state_mutex); + //unknown screen state + ilits->screen_state = SCREEN_UNKNOWN; + if (!initialized_sensor) { +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_init(&(ilits->gesture_wakelock), WAKE_LOCK_SUSPEND, "dt-wake-lock"); +#else + wakeup_source_init(&(ilits->gesture_wakelock), "dt-wake-lock"); +#endif + if (!ili_sensor_init(ilits)) + initialized_sensor = true; + } +#endif ILI_INFO("ILITEK Driver loaded successfully!"); return 0; } diff --git a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_touch.c b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_touch.c index 009bad296379..ae84c29854bc 100644 --- a/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_touch.c +++ b/drivers/input/touchscreen/ilitek_0flash_mmi/ilitek_touch.c @@ -1100,8 +1100,13 @@ void ili_report_gesture_mode(u8 *buf, int len) int i, lu_x = 0, lu_y = 0, rd_x = 0, rd_y = 0, score = 0; u8 ges[P5_X_GESTURE_INFO_LENGTH] = {0}; struct gesture_coordinate *gc = ilits->gcoord; +#ifndef ILI_SENSOR_EN struct input_dev *input = ilits->input; +#endif bool transfer = ilits->trans_xy; +#ifdef ILI_SENSOR_EN + static int report_cnt = 0; +#endif for (i = 0; i < len; i++) ges[i] = buf[i]; @@ -1129,10 +1134,38 @@ void ili_report_gesture_mode(u8 *buf, int len) switch (gc->code) { case GESTURE_DOUBLECLICK: ILI_INFO("Double Click key event\n"); +#ifdef ILI_SENSOR_EN + if (!(ilits->wakeable && ilits->should_enable_gesture)) { + ILI_INFO("Gesture got but wakeable not set. Skip this gesture."); + return; + } + if (ilits->report_gesture_key) { + input_report_key(ilits->sensor_pdata->input_sensor_dev, KEY_F1, 1); + input_sync(ilits->sensor_pdata->input_sensor_dev); + input_report_key(ilits->sensor_pdata->input_sensor_dev, KEY_F1, 0); + input_sync(ilits->sensor_pdata->input_sensor_dev); + ++report_cnt; + } else { + input_report_abs(ilits->sensor_pdata->input_sensor_dev, + ABS_DISTANCE, + ++report_cnt); + input_sync(ilits->sensor_pdata->input_sensor_dev); + } + ILI_INFO("input report: %d", report_cnt); + if (report_cnt >= REPORT_MAX_COUNT) { + report_cnt = 0; + } +#ifdef CONFIG_HAS_WAKELOCK + wake_lock_timeout(&(ilits->gesture_wakelock), msecs_to_jiffies(5000)); +#else + __pm_wakeup_event(&(ilits->gesture_wakelock), 5000); +#endif +#else input_report_key(input, KEY_GESTURE_POWER, 1); input_sync(input); input_report_key(input, KEY_GESTURE_POWER, 0); input_sync(input); +#endif gc->type = GESTURE_DOUBLECLICK; gc->clockwise = 1; gc->pos_end.x = gc->pos_start.x;