476 lines
13 KiB
C
476 lines
13 KiB
C
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||
|
/*
|
||
|
* Copyright (C) 2016 MediaTek Inc.
|
||
|
*/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* 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
|
||
|
|
||
|
/*****************************************************************************
|
||
|
* Private enumerations, structures and unions using typedef
|
||
|
*****************************************************************************/
|
||
|
/*
|
||
|
* gesture_id - mean which gesture is recognised
|
||
|
* point_num - points number of this gesture
|
||
|
* coordinate_x - All gesture point x coordinate
|
||
|
* coordinate_y - All gesture point y coordinate
|
||
|
* mode - gesture enable/disable, need enable by host
|
||
|
* - 1:enable gesture function(default) 0:disable
|
||
|
* active - gesture work flag,
|
||
|
* always set 1 when suspend, set 0 when resume
|
||
|
*/
|
||
|
struct fts_gesture_st {
|
||
|
u8 gesture_id;
|
||
|
u8 point_num;
|
||
|
u16 coordinate_x[FTS_GESTURE_POINTS_MAX];
|
||
|
u16 coordinate_y[FTS_GESTURE_POINTS_MAX];
|
||
|
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_mode_show(struct device *dev,
|
||
|
struct DEVICE_ATTR_RWibute *attr, char *buf)
|
||
|
{
|
||
|
int count = 0;
|
||
|
u8 val = 0;
|
||
|
struct input_dev *input_dev = fts_data->input_dev;
|
||
|
|
||
|
mutex_lock(&input_dev->mutex);
|
||
|
fts_read_reg(FTS_REG_GESTURE_EN, &val);
|
||
|
count = snprintf(buf, PAGE_SIZE, "Gesture Mode:%s\n",
|
||
|
fts_gesture_data.mode ? "On" : "Off");
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "Reg(0xD0)=%d\n", val);
|
||
|
mutex_unlock(&input_dev->mutex);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t fts_gesture_mode_store(struct device *dev,
|
||
|
struct DEVICE_ATTR_RWibute *attr, const char *buf,
|
||
|
size_t count)
|
||
|
{
|
||
|
struct input_dev *input_dev = fts_data->input_dev;
|
||
|
|
||
|
mutex_lock(&input_dev->mutex);
|
||
|
if (FTS_SYSFS_ECHO_ON(buf)) {
|
||
|
FTS_DEBUG("enable gesture");
|
||
|
fts_gesture_data.mode = ENABLE;
|
||
|
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
|
||
|
FTS_DEBUG("disable gesture");
|
||
|
fts_gesture_data.mode = DISABLE;
|
||
|
}
|
||
|
mutex_unlock(&input_dev->mutex);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t fts_gesture_buf_show(struct device *dev,
|
||
|
struct DEVICE_ATTR_RWibute *attr, char *buf)
|
||
|
{
|
||
|
int count = 0;
|
||
|
int i = 0;
|
||
|
struct input_dev *input_dev = fts_data->input_dev;
|
||
|
struct fts_gesture_st *gesture = &fts_gesture_data;
|
||
|
|
||
|
mutex_lock(&input_dev->mutex);
|
||
|
count = snprintf(buf, PAGE_SIZE, "Gesture ID:%d\n",
|
||
|
gesture->gesture_id);
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum:%d\n",
|
||
|
gesture->point_num);
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "Gesture Points Buffer:\n");
|
||
|
|
||
|
/* save point data,max:6 */
|
||
|
for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) {
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i,
|
||
|
gesture->coordinate_x[i],
|
||
|
gesture->coordinate_y[i]);
|
||
|
if ((i + 1) % 4 == 0)
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "\n");
|
||
|
}
|
||
|
count += snprintf(buf + count, PAGE_SIZE, "\n");
|
||
|
mutex_unlock(&input_dev->mutex);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t fts_gesture_buf_store(struct device *dev,
|
||
|
struct DEVICE_ATTR_RWibute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
return -EPERM;
|
||
|
}
|
||
|
|
||
|
/* sysfs gesture node
|
||
|
* read example: cat fts_gesture_mode ---read gesture mode
|
||
|
* write example:echo 1 > fts_gesture_mode --- write gesture mode to 1
|
||
|
*
|
||
|
*/
|
||
|
static DEVICE_ATTR_RW(fts_gesture_mode, 0644, fts_gesture_mode_show,
|
||
|
fts_gesture_mode_store);
|
||
|
/*
|
||
|
* read example: cat fts_gesture_buf --- read gesture buf
|
||
|
*/
|
||
|
static DEVICE_ATTR_RW(fts_gesture_buf, 0644, 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,
|
||
|
};
|
||
|
|
||
|
int fts_create_gesture_sysfs(struct device *dev)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
ret = sysfs_create_group(&dev->kobj, &fts_gesture_group);
|
||
|
if (ret) {
|
||
|
FTS_ERROR("gesture sys node create fail");
|
||
|
sysfs_remove_group(&dev->kobj, &fts_gesture_group);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void fts_gesture_report(struct input_dev *input_dev, int gesture_id)
|
||
|
{
|
||
|
int gesture;
|
||
|
|
||
|
FTS_DEBUG("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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
* Name: fts_gesture_readdata
|
||
|
* Brief: Read information about gesture: enable flag/gesture points..., if ges-
|
||
|
* true enable, save gesture points' information, and report to OS.
|
||
|
* It will be called this function every interrupt when FTS_GESTURE_EN = 1
|
||
|
*
|
||
|
* gesture data length: 1(enable) + 1(reserve) + 2(header) + 6 * 4
|
||
|
* Input: ts_data - global struct data
|
||
|
* data - gesture data buffer if non-flash, else NULL
|
||
|
* Output:
|
||
|
* Return: 0 - read gesture data successfully, the report data is gesture data
|
||
|
* 1 - tp not in suspend/gesture not enable in TP FW
|
||
|
* -Exx - error
|
||
|
*****************************************************************************/
|
||
|
int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
int i = 0;
|
||
|
int index = 0;
|
||
|
u8 buf[FTS_GESTURE_DATA_LEN] = {0};
|
||
|
struct input_dev *input_dev = ts_data->input_dev;
|
||
|
struct fts_gesture_st *gesture = &fts_gesture_data;
|
||
|
|
||
|
if (!ts_data->suspended || (gesture->mode == DISABLE))
|
||
|
return 1;
|
||
|
|
||
|
|
||
|
ret = fts_read_reg(FTS_REG_GESTURE_EN, &buf[0]);
|
||
|
if ((ret < 0) || (buf[0] != ENABLE)) {
|
||
|
FTS_DEBUG("gesture not enable in fw, don't process gesture");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
buf[2] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
|
||
|
ret = fts_read(&buf[2], 1, &buf[2], FTS_GESTURE_DATA_LEN - 2);
|
||
|
if (ret < 0) {
|
||
|
FTS_ERROR("read gesture header data fail");
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* init variable before read gesture point */
|
||
|
memset(gesture->coordinate_x, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16));
|
||
|
memset(gesture->coordinate_y, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16));
|
||
|
gesture->gesture_id = buf[2];
|
||
|
gesture->point_num = buf[3];
|
||
|
FTS_DEBUG("gesture_id=%d, point_num=%d", gesture->gesture_id,
|
||
|
gesture->point_num);
|
||
|
|
||
|
/* save point data,max:6 */
|
||
|
for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) {
|
||
|
index = 4 * i + 4;
|
||
|
gesture->coordinate_x[i] =
|
||
|
(u16)(((buf[0 + index] & 0x0F) << 8) + buf[1 + index]);
|
||
|
gesture->coordinate_y[i] =
|
||
|
(u16)(((buf[2 + index] & 0x0F) << 8) + buf[3 + index]);
|
||
|
}
|
||
|
|
||
|
/* report gesture to OS */
|
||
|
fts_gesture_report(input_dev, gesture->gesture_id);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void fts_gesture_recovery(struct fts_ts_data *ts_data)
|
||
|
{
|
||
|
if ((fts_gesture_data.mode == ENABLE) &&
|
||
|
(fts_gesture_data.active == ENABLE)) {
|
||
|
FTS_DEBUG("gesture recovery...");
|
||
|
fts_write_reg(0xD1, 0xFF);
|
||
|
fts_write_reg(0xD2, 0xFF);
|
||
|
fts_write_reg(0xD5, 0xFF);
|
||
|
fts_write_reg(0xD6, 0xFF);
|
||
|
fts_write_reg(0xD7, 0xFF);
|
||
|
fts_write_reg(0xD8, 0xFF);
|
||
|
fts_write_reg(FTS_REG_GESTURE_EN, ENABLE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int fts_gesture_suspend(struct fts_ts_data *ts_data)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
int i = 0;
|
||
|
u8 state = 0xFF;
|
||
|
|
||
|
FTS_INFO("gesture suspend...");
|
||
|
/* gesture not enable, return immediately */
|
||
|
if (fts_gesture_data.mode == DISABLE) {
|
||
|
FTS_DEBUG("gesture is disabled");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 5; i++) {
|
||
|
fts_write_reg(0xD1, 0xFF);
|
||
|
fts_write_reg(0xD2, 0xFF);
|
||
|
fts_write_reg(0xD5, 0xFF);
|
||
|
fts_write_reg(0xD6, 0xFF);
|
||
|
fts_write_reg(0xD7, 0xFF);
|
||
|
fts_write_reg(0xD8, 0xFF);
|
||
|
fts_write_reg(FTS_REG_GESTURE_EN, ENABLE);
|
||
|
msleep(20);
|
||
|
fts_read_reg(FTS_REG_GESTURE_EN, &state);
|
||
|
if (state == ENABLE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i >= 5) {
|
||
|
FTS_ERROR("Enter into gesture(suspend) fail");
|
||
|
fts_gesture_data.active = DISABLE;
|
||
|
return -EIO;
|
||
|
}
|
||
|
|
||
|
ret = enable_irq_wake(ts_data->irq);
|
||
|
if (ret)
|
||
|
FTS_DEBUG("enable_irq_wake(irq:%d) fail", ts_data->irq);
|
||
|
|
||
|
|
||
|
fts_gesture_data.active = ENABLE;
|
||
|
FTS_INFO("Enter into gesture(suspend) successfully!");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int fts_gesture_resume(struct fts_ts_data *ts_data)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
int i = 0;
|
||
|
u8 state = 0xFF;
|
||
|
|
||
|
FTS_INFO("gesture resume...");
|
||
|
/* gesture not enable, return immediately */
|
||
|
if (fts_gesture_data.mode == DISABLE) {
|
||
|
FTS_DEBUG("gesture is disabled");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
if (fts_gesture_data.active == DISABLE) {
|
||
|
FTS_DEBUG("gesture active is disable, return immediately");
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
fts_gesture_data.active = DISABLE;
|
||
|
for (i = 0; i < 5; i++) {
|
||
|
fts_write_reg(FTS_REG_GESTURE_EN, DISABLE);
|
||
|
msleep(20);
|
||
|
fts_read_reg(FTS_REG_GESTURE_EN, &state);
|
||
|
if (state == DISABLE)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i >= 5) {
|
||
|
FTS_ERROR("exit gesture(resume) fail");
|
||
|
return -EIO;
|
||
|
}
|
||
|
|
||
|
ret = disable_irq_wake(ts_data->irq);
|
||
|
if (ret)
|
||
|
FTS_DEBUG("disable_irq_wake(irq:%d) fail", ts_data->irq);
|
||
|
|
||
|
|
||
|
FTS_INFO("resume from gesture successfully");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int fts_gesture_init(struct fts_ts_data *ts_data)
|
||
|
{
|
||
|
struct input_dev *input_dev = ts_data->input_dev;
|
||
|
|
||
|
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(ts_data->dev);
|
||
|
|
||
|
memset(&fts_gesture_data, 0, sizeof(struct fts_gesture_st));
|
||
|
fts_gesture_data.mode = ENABLE;
|
||
|
fts_gesture_data.active = DISABLE;
|
||
|
|
||
|
FTS_FUNC_EXIT();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int fts_gesture_exit(struct fts_ts_data *ts_data)
|
||
|
{
|
||
|
FTS_FUNC_ENTER();
|
||
|
sysfs_remove_group(&ts_data->dev->kobj, &fts_gesture_group);
|
||
|
FTS_FUNC_EXIT();
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|