/* * * FocalTech TouchScreen driver. * * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ /***************************************************************************** * * File Name: focaltech_gestrue.c * * Author: Focaltech Driver Team * * Created: 2016-08-08 * * Abstract: * * Reference: * *****************************************************************************/ /***************************************************************************** * 1.Included header files *****************************************************************************/ #include "focaltech_core.h" #if FTS_GESTURE_EN /****************************************************************************** * Private constant and macro definitions using #define *****************************************************************************/ #define KEY_GESTURE_U KEY_U #define KEY_GESTURE_UP KEY_UP #define KEY_GESTURE_DOWN KEY_DOWN #define KEY_GESTURE_LEFT KEY_LEFT #define KEY_GESTURE_RIGHT KEY_RIGHT #define KEY_GESTURE_O KEY_O #define KEY_GESTURE_E KEY_E #define KEY_GESTURE_M KEY_M #define KEY_GESTURE_L KEY_L #define KEY_GESTURE_W KEY_W #define KEY_GESTURE_S KEY_S #define KEY_GESTURE_V KEY_V #define KEY_GESTURE_C KEY_C #define KEY_GESTURE_Z KEY_Z #define GESTURE_LEFT 0x20 #define GESTURE_RIGHT 0x21 #define GESTURE_UP 0x22 #define GESTURE_DOWN 0x23 #define GESTURE_DOUBLECLICK 0x24 #define GESTURE_O 0x30 #define GESTURE_W 0x31 #define GESTURE_M 0x32 #define GESTURE_E 0x33 #define GESTURE_L 0x44 #define GESTURE_S 0x46 #define GESTURE_V 0x54 #define GESTURE_Z 0x41 #define GESTURE_C 0x34 #define FTS_GESTRUE_POINTS 255 #define FTS_GESTRUE_POINTS_HEADER 8 /***************************************************************************** * Private enumerations, structures and unions using typedef *****************************************************************************/ /* * header - byte0:gesture id * byte1:pointnum * byte2~7:reserved * coordinate_x - All gesture point x coordinate * coordinate_y - All gesture point y coordinate * mode - 1:enable gesture function(default) * - 0:disable * active - 1:enter into gesture(suspend) * 0:gesture disable or resume */ struct fts_gesture_st { u8 header[FTS_GESTRUE_POINTS_HEADER]; u16 coordinate_x[FTS_GESTRUE_POINTS]; u16 coordinate_y[FTS_GESTRUE_POINTS]; u8 mode; u8 active; }; /***************************************************************************** * Static variables *****************************************************************************/ static struct fts_gesture_st fts_gesture_data; /***************************************************************************** * Global variable or extern global variabls/functions *****************************************************************************/ /***************************************************************************** * Static function prototypes *****************************************************************************/ static ssize_t fts_gesture_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t fts_gesture_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); static ssize_t fts_gesture_buf_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t fts_gesture_buf_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); /* sysfs gesture node * read example: cat fts_gesture_mode ---read gesture mode * write example:echo 01 > fts_gesture_mode ---write gesture mode to 01 * */ static DEVICE_ATTR (fts_gesture_mode, S_IRUGO|S_IWUSR, fts_gesture_show, fts_gesture_store); /* * read example: cat fts_gesture_buf ---read gesture buf */ static DEVICE_ATTR (fts_gesture_buf, S_IRUGO|S_IWUSR, fts_gesture_buf_show, fts_gesture_buf_store); static struct attribute *fts_gesture_mode_attrs[] = { &dev_attr_fts_gesture_mode.attr, &dev_attr_fts_gesture_buf.attr, NULL, }; static struct attribute_group fts_gesture_group = { .attrs = fts_gesture_mode_attrs, }; /************************************************************************ * Name: fts_gesture_show * Brief: * Input: device, device attribute, char buf * Output: * Return: ***********************************************************************/ static ssize_t fts_gesture_show(struct device *dev, struct device_attribute *attr, char *buf) { int count; u8 val; struct i2c_client *client = container_of(dev, struct i2c_client, dev); mutex_lock(&fts_input_dev->mutex); fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &val); count = sprintf(buf, "Gesture Mode: %s\n", fts_gesture_data.mode ? "On" : "Off"); count += sprintf(buf + count, "Reg(0xD0) = %d\n", val); mutex_unlock(&fts_input_dev->mutex); return count; } /************************************************************************ * Name: fts_gesture_store * Brief: * Input: device, device attribute, char buf, char count * Output: * Return: ***********************************************************************/ static ssize_t fts_gesture_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { mutex_lock(&fts_input_dev->mutex); if (FTS_SYSFS_ECHO_ON(buf)) { FTS_INFO("[GESTURE]enable gesture"); fts_gesture_data.mode = ENABLE; } else if (FTS_SYSFS_ECHO_OFF(buf)) { FTS_INFO("[GESTURE]disable gesture"); fts_gesture_data.mode = DISABLE; } mutex_unlock(&fts_input_dev->mutex); return count; } /************************************************************************ * Name: fts_gesture_buf_show * Brief: * Input: device, device attribute, char buf * Output: * Return: ***********************************************************************/ static ssize_t fts_gesture_buf_show(struct device *dev, struct device_attribute *attr, char *buf) { int count; int i = 0; mutex_lock(&fts_input_dev->mutex); count = snprintf(buf, PAGE_SIZE, "Gesture ID: 0x%x\n", fts_gesture_data.header[0]); count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum: %d\n", fts_gesture_data.header[1]); count += snprintf(buf + count, PAGE_SIZE, "Gesture Point Buf:\n"); for (i = 0; i < fts_gesture_data.header[1]; i++) { count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i, fts_gesture_data.coordinate_x[i], fts_gesture_data.coordinate_y[i]); if ((i + 1)%4 == 0) count += snprintf(buf + count, PAGE_SIZE, "\n"); } count += snprintf(buf + count, PAGE_SIZE, "\n"); mutex_unlock(&fts_input_dev->mutex); return count; } /************************************************************************ * Name: fts_gesture_buf_store * Brief: * Input: device, device attribute, char buf, char count * Output: * Return: ***********************************************************************/ static ssize_t fts_gesture_buf_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { /* place holder for future use */ return -EPERM; } /***************************************************************************** * Name: fts_create_gesture_sysfs * Brief: * Input: * Output: * Return: 0-success or others-error *****************************************************************************/ int fts_create_gesture_sysfs(struct i2c_client *client) { int ret = 0; ret = sysfs_create_group(&client->dev.kobj, &fts_gesture_group); if ( ret != 0) { FTS_ERROR( "[GESTURE]fts_gesture_mode_group(sysfs) create failed!"); sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); return ret; } return 0; } /***************************************************************************** * Name: fts_gesture_report * Brief: * Input: * Output: * Return: *****************************************************************************/ static void fts_gesture_report(struct input_dev *input_dev,int gesture_id) { int gesture; FTS_FUNC_ENTER(); FTS_DEBUG("fts gesture_id==0x%x ",gesture_id); switch (gesture_id) { case GESTURE_LEFT: gesture = KEY_GESTURE_LEFT; break; case GESTURE_RIGHT: gesture = KEY_GESTURE_RIGHT; break; case GESTURE_UP: gesture = KEY_GESTURE_UP; break; case GESTURE_DOWN: gesture = KEY_GESTURE_DOWN; break; case GESTURE_DOUBLECLICK: gesture = KEY_GESTURE_U; break; case GESTURE_O: gesture = KEY_GESTURE_O; break; case GESTURE_W: gesture = KEY_GESTURE_W; break; case GESTURE_M: gesture = KEY_GESTURE_M; break; case GESTURE_E: gesture = KEY_GESTURE_E; break; case GESTURE_L: gesture = KEY_GESTURE_L; break; case GESTURE_S: gesture = KEY_GESTURE_S; break; case GESTURE_V: gesture = KEY_GESTURE_V; break; case GESTURE_Z: gesture = KEY_GESTURE_Z; break; case GESTURE_C: gesture = KEY_GESTURE_C; break; default: gesture = -1; break; } /* report event key */ if (gesture != -1) { FTS_DEBUG("Gesture Code=%d", gesture); input_report_key(input_dev, gesture, 1); input_sync(input_dev); input_report_key(input_dev, gesture, 0); input_sync(input_dev); } FTS_FUNC_EXIT(); } /************************************************************************ * Name: fts_gesture_readdata * Brief: read data from TP register * Input: * Output: * Return: fail <0 ***********************************************************************/ static int fts_gesture_read_buffer(struct i2c_client *client, u8 *buf, int read_bytes) { int remain_bytes; int ret; int i; if (read_bytes <= I2C_BUFFER_LENGTH_MAXINUM) { ret = fts_i2c_read(client, buf, 1, buf, read_bytes); } else { ret = fts_i2c_read(client, buf, 1, buf, I2C_BUFFER_LENGTH_MAXINUM); remain_bytes = read_bytes - I2C_BUFFER_LENGTH_MAXINUM; for (i = 1; remain_bytes > 0; i++) { if (remain_bytes <= I2C_BUFFER_LENGTH_MAXINUM) ret = fts_i2c_read(client, buf, 0, buf + I2C_BUFFER_LENGTH_MAXINUM * i, remain_bytes); else ret = fts_i2c_read(client, buf, 0, buf + I2C_BUFFER_LENGTH_MAXINUM * i, I2C_BUFFER_LENGTH_MAXINUM); remain_bytes -= I2C_BUFFER_LENGTH_MAXINUM; } } return ret; } /************************************************************************ * Name: fts_gesture_fw * Brief: Check IC's gesture recognise by FW or not * Input: * Output: * Return: 1- FW 0- Driver ***********************************************************************/ static int fts_gesture_fw(void) { int ret = 0; switch (chip_types.chip_idh) { case 0x54: case 0x58: case 0x64: case 0x87: case 0x86: case 0x80: case 0xE7: ret = 1; break; default: ret = 0; break; } return ret; } /************************************************************************ * Name: fts_gesture_readdata * Brief: read data from TP register * Input: * Output: * Return: fail <0 ***********************************************************************/ int fts_gesture_readdata(struct i2c_client *client) { u8 buf[FTS_GESTRUE_POINTS * 4] = { 0 }; int ret = -1; int i = 0; int gestrue_id = 0; int read_bytes = 0; u8 pointnum; FTS_FUNC_ENTER(); /* init variable before read gesture point */ memset(fts_gesture_data.header, 0, FTS_GESTRUE_POINTS_HEADER); memset(fts_gesture_data.coordinate_x, 0, FTS_GESTRUE_POINTS * sizeof(u16)); memset(fts_gesture_data.coordinate_y, 0, FTS_GESTRUE_POINTS * sizeof(u16)); buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; ret = fts_i2c_read(client, buf, 1, buf, FTS_GESTRUE_POINTS_HEADER); if (ret < 0) { FTS_ERROR("[GESTURE]Read gesture header data failed!!"); FTS_FUNC_EXIT(); return ret; } /* FW recognize gesture */ if (fts_gesture_fw()) { memcpy(fts_gesture_data.header, buf, FTS_GESTRUE_POINTS_HEADER); gestrue_id = buf[0]; pointnum = buf[1]; read_bytes = ((int)pointnum) * 4 + 2; buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; FTS_DEBUG("[GESTURE]PointNum=%d", pointnum); ret = fts_gesture_read_buffer(client, buf, read_bytes); if (ret < 0) { FTS_ERROR("[GESTURE]Read gesture touch data failed!!"); FTS_FUNC_EXIT(); return ret; } fts_gesture_report(fts_input_dev,gestrue_id); for (i = 0; i < pointnum; i++) { fts_gesture_data.coordinate_x[i] = (((s16) buf[0 + (4 * i + 2)]) & 0x0F) << 8 | (((s16) buf[1 + (4 * i + 2)]) & 0xFF); fts_gesture_data.coordinate_y[i] = (((s16) buf[2 + (4 * i + 2)]) & 0x0F) << 8 | (((s16) buf[3 + (4 * i + 2)]) & 0xFF); } FTS_FUNC_EXIT(); return 0; } else { FTS_ERROR("[GESTURE]IC 0x%x need gesture lib to support gestures.", chip_types.chip_idh); return 0; } #if 0 /* other IC's gestrue in driver, need gesture library */ if (0x24 == buf[0]) { gestrue_id = 0x24; fts_gesture_report(fts_input_dev, gestrue_id); FTS_DEBUG("[GESTURE]%d check_gesture gestrue_id", gestrue_id); FTS_FUNC_EXIT(); return -1; } /* Host Driver recognize gesture */ pointnum = buf[1]; read_bytes = ((int)pointnum) * 4 + 2; buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; ret = fts_gesture_read_buffer(client, buf, read_bytes); if (ret < 0) { FTS_ERROR("[GESTURE]Driver recognize gesture - Read gesture touch data failed!!"); FTS_FUNC_EXIT(); return ret; } /* * Host Driver recognize gesture, need gesture lib.a * Not use now for compatibility */ gestrue_id = fetch_object_sample(buf, pointnum); fts_gesture_report(fts_input_dev, gestrue_id); FTS_DEBUG("[GESTURE]%d read gestrue_id", gestrue_id); for (i = 0; i < pointnum; i++) { fts_gesture_data.coordinate_x[i] = (((s16) buf[0 + (4 * i+8)]) & 0x0F) << 8 | (((s16) buf[1 + (4 * i+8)])& 0xFF); fts_gesture_data.coordinate_y[i] = (((s16) buf[2 + (4 * i+8)]) & 0x0F) << 8 | (((s16) buf[3 + (4 * i+8)]) & 0xFF); } FTS_FUNC_EXIT(); return -1; #endif } /***************************************************************************** * Name: fts_gesture_recovery * Brief: recovery gesture state when reset or power on * Input: * Output: * Return: *****************************************************************************/ void fts_gesture_recovery(struct i2c_client *client) { if (fts_gesture_data.mode && fts_gesture_data.active) { fts_i2c_write_reg(client, 0xD1, 0xff); fts_i2c_write_reg(client, 0xD2, 0xff); fts_i2c_write_reg(client, 0xD5, 0xff); fts_i2c_write_reg(client, 0xD6, 0xff); fts_i2c_write_reg(client, 0xD7, 0xff); fts_i2c_write_reg(client, 0xD8, 0xff); fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, ENABLE); } } /***************************************************************************** * Name: fts_gesture_suspend * Brief: * Input: * Output: None * Return: None *****************************************************************************/ int fts_gesture_suspend(struct i2c_client *i2c_client) { int i; u8 state; FTS_FUNC_ENTER(); /* gesture not enable, return immediately */ if (fts_gesture_data.mode == 0) { FTS_DEBUG("gesture is disabled"); FTS_FUNC_EXIT(); return -1; } for (i = 0; i < 5; i++) { fts_i2c_write_reg(i2c_client, 0xd1, 0xff); fts_i2c_write_reg(i2c_client, 0xd2, 0xff); fts_i2c_write_reg(i2c_client, 0xd5, 0xff); fts_i2c_write_reg(i2c_client, 0xd6, 0xff); fts_i2c_write_reg(i2c_client, 0xd7, 0xff); fts_i2c_write_reg(i2c_client, 0xd8, 0xff); fts_i2c_write_reg(i2c_client, FTS_REG_GESTURE_EN, 0x01); msleep(1); fts_i2c_read_reg(i2c_client, FTS_REG_GESTURE_EN, &state); if (state == 1) break; } if (i >= 5) { FTS_ERROR("[GESTURE]Enter into gesture(suspend) failed!\n"); FTS_FUNC_EXIT(); return -1; } fts_gesture_data.active = 1; FTS_DEBUG("[GESTURE]Enter into gesture(suspend) successfully!"); FTS_FUNC_EXIT(); return 0; } /***************************************************************************** * Name: fts_gesture_resume * Brief: * Input: * Output: None * Return: None *****************************************************************************/ int fts_gesture_resume(struct i2c_client *client) { int i; u8 state; FTS_FUNC_ENTER(); /* gesture not enable, return immediately */ if (fts_gesture_data.mode == 0) { FTS_DEBUG("gesture is disabled"); FTS_FUNC_EXIT(); return -1; } if (fts_gesture_data.active == 0) { FTS_DEBUG("gesture is unactive"); FTS_FUNC_EXIT(); return -1; } fts_gesture_data.active = 0; for (i = 0; i < 5; i++) { fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, 0x00); msleep(1); fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &state); if (state == 0) break; } if (i >= 5) { FTS_ERROR("[GESTURE]Clear gesture(resume) failed!\n"); } FTS_FUNC_EXIT(); return 0; } /***************************************************************************** * Name: fts_gesture_init * Brief: * Input: * Output: None * Return: None *****************************************************************************/ int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client) { FTS_FUNC_ENTER(); input_set_capability(input_dev, EV_KEY, KEY_POWER); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z); input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C); __set_bit(KEY_GESTURE_RIGHT, input_dev->keybit); __set_bit(KEY_GESTURE_LEFT, input_dev->keybit); __set_bit(KEY_GESTURE_UP, input_dev->keybit); __set_bit(KEY_GESTURE_DOWN, input_dev->keybit); __set_bit(KEY_GESTURE_U, input_dev->keybit); __set_bit(KEY_GESTURE_O, input_dev->keybit); __set_bit(KEY_GESTURE_E, input_dev->keybit); __set_bit(KEY_GESTURE_M, input_dev->keybit); __set_bit(KEY_GESTURE_W, input_dev->keybit); __set_bit(KEY_GESTURE_L, input_dev->keybit); __set_bit(KEY_GESTURE_S, input_dev->keybit); __set_bit(KEY_GESTURE_V, input_dev->keybit); __set_bit(KEY_GESTURE_C, input_dev->keybit); __set_bit(KEY_GESTURE_Z, input_dev->keybit); fts_create_gesture_sysfs(client); fts_gesture_data.mode = 1; fts_gesture_data.active = 0; FTS_FUNC_EXIT(); return 0; } /************************************************************************ * Name: fts_gesture_exit * Brief: call when driver removed * Input: * Output: * Return: ***********************************************************************/ int fts_gesture_exit(struct i2c_client *client) { FTS_FUNC_ENTER(); sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); FTS_FUNC_EXIT(); return 0; } #endif