Merge "input: touchscreen: Enable FTS Touch driver"

This commit is contained in:
qctecmdr 2020-01-22 11:55:37 -08:00 • committed by Gerrit - the friendly Code Review server
commit 9cf1fba397
32 changed files with 17926 additions and 4 deletions

View file

@ -278,7 +278,6 @@ config TOUCHSCREEN_CYTTSP4_SPI
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
default y
help
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
@ -824,7 +823,6 @@ config TOUCHSCREEN_WM97XX
config TOUCHSCREEN_WM9705
bool "WM9705 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9705 touchscreen controller.
@ -832,7 +830,6 @@ config TOUCHSCREEN_WM9705
config TOUCHSCREEN_WM9712
bool "WM9712 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9712 touchscreen controller.
@ -840,7 +837,6 @@ config TOUCHSCREEN_WM9712
config TOUCHSCREEN_WM9713
bool "WM9713 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX
default y
help
Say Y here to enable support for the Wolfson Microelectronics
WM9713 touchscreen controller.
@ -1314,4 +1310,6 @@ config TOUCHSCREEN_IQS5XX
To compile this driver as a module, choose M here: the
module will be called iqs5xx.
source "drivers/input/touchscreen/st/Kconfig"
endif

View file

@ -110,3 +110,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
obj-$(CONFIG_TOUCHSCREEN_ST) += st/

View file

@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# STMicroelectronics touchscreen driver configuration
#
config TOUCHSCREEN_ST
tristate "STMicroelectronics Touchscreen Driver"
depends on I2C
help
Say Y here if you have a STMicroelectronics Touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called st.
config TOUCHSCREEN_ST_I2C
#tristate "STMicroelectronics i2c touchscreen"
string "STMicroelectronics ts directory name"
default "st"
depends on TOUCHSCREEN_ST
help
This enables support for ST touch panel over I2C based touchscreens.

View file

@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
#
## Makefile for the STMicroelectronics touchscreen driver.
#
obj-$(CONFIG_TOUCHSCREEN_ST) += st_fts.o
st_fts-y := fts.o fts_gui.o fts_driver_test.o fts_aoi_event.o \
fts_lib/ftsCompensation.o fts_lib/ftsCrossCompile.o fts_lib/ftsError.o \
fts_lib/ftsFrame.o fts_lib/ftsIO.o fts_lib/ftsTest.o fts_lib/ftsTime.o \
fts_lib/ftsTool.o fts_lib/ftsFlash.o fts_lib/ftsGesture.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,350 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LINUX_FTS_I2C_H_
#define _LINUX_FTS_I2C_H_
/*#include <linux/wakelock.h>*/
#include <linux/pm_wakeup.h>
#include <linux/timekeeping.h>
#include "fts_lib/ftsSoftware.h"
#include "fts_lib/ftsHardware.h"
#include "fts_lib/ftsGesture.h"
#define FTS_POWER_ON 1
#define FTS_POWER_OFF 0
/****************** CONFIGURATION SECTION ******************/
/**** CODE CONFIGURATION ****/
#define FTS_TS_DRV_NAME "fts"
#define FTS_TS_DRV_VERSION "4.2.14" /* version */
/*#define SCRIPTLESS*/ /*allow to work in scriptless mode with the GUI*/
#ifdef SCRIPTLESS
#define SCRIPTLESS_DEBUG
/**
* uncomment this macro definition to print debug
* message for script less support
*/
#endif
#define DRIVER_TEST
/* #define FW_H_FILE */ /*include the FW as header file*/
#ifdef FW_H_FILE
#define FW_SIZE_NAME myArray_size
#define FW_ARRAY_NAME myArray
#endif
/*#define LIMITS_H_FILE*/ /*include the limits file as header file*/
#ifdef LIMITS_H_FILE
#define LIMITS_SIZE_NAME myArray2_size
#define LIMITS_ARRAY_NAME myArray2
#endif
/**** END ****/
/**** FEATURES USED IN THE IC ***/
/* #define PHONE_KEY enable the keys */
#define PHONE_GESTURE /*allow to use the gestures*/
#ifdef PHONE_GESTURE
#define USE_GESTURE_MASK
#define USE_CUSTOM_GESTURES
#endif
#define USE_ONE_FILE_NODE
/*allow to enable/disable all the features just using one file node*/
#define EDGE_REJ
/*allow edge rej feature (comment to disable)*/
#define CORNER_REJ
/*allow corn rej feature (comment to disable)*/
#define EDGE_PALM_REJ
/*allow edge palm rej feature (comment to disable)*/
#define CHARGER_MODE
/*allow charger mode feature (comment to disable)*/
#define GLOVE_MODE
/*allow glove mode feature (comment to disable)*/
#define VR_MODE
/*allow vr mode feature (comment to disable)*/
#define COVER_MODE
/*allow cover mode feature (comment to disable)*/
#define STYLUS_MODE
/*allow stylus mode feature (comment to disable)*/
#define USE_NOISE_PARAM
/*set noise params during resume (comment to disable)*/
/**** END ****/
/**** PANEL SPECIFICATION ****/
#define X_AXIS_MAX 1440
#define X_AXIS_MIN 0
#define Y_AXIS_MAX 2880
#define Y_AXIS_MIN 0
#define PRESSURE_MIN 0
#define PRESSURE_MAX 127
#define TOUCH_ID_MAX 10
#define AREA_MIN PRESSURE_MIN
#define AREA_MAX PRESSURE_MAX
/**** END ****/
/*********************************************************/
/* Flash programming */
#define INIT_FLAG_CNT 3
/* KEYS */
#define KEY1 0x02
#define KEY2 0x01
#define KEY3 0x04
/*
* Configuration mode
*/
/**
* bitmask which can assume the value defined as
* features in ftsSoftware.h or the following values
*/
#define MODE_NOTHING 0x00000000
#define MODE_SENSEON 0x10000000
#define MODE_SENSEOFF 0x20000000
#define FEAT_GESTURE 0x40000000
/*
* Status Event Field:
* id of command that triggered the event
*/
#define FTS_FLASH_WRITE_CONFIG 0x03
#define FTS_FLASH_WRITE_COMP_MEMORY 0x04
#define FTS_FORCE_CAL_SELF_MUTUAL 0x05
#define FTS_FORCE_CAL_SELF 0x06
#define FTS_WATER_MODE_ON 0x07
#define FTS_WATER_MODE_OFF 0x08
#define EXP_FN_WORK_DELAY_MS 1000
#define CMD_STR_LEN 32
#define I2C_DATA_MAX_LEN 32
#ifdef SCRIPTLESS
/*
* I2C Command Read/Write Function
*/
#define CMD_RESULT_STR_LEN 2048
#endif
#define TSP_BUF_SIZE 4096
#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
/*add by guchong*/
#ifdef PHONE_GESTURE
extern u16 gesture_coordinates_x[GESTURE_COORDS_REPORT_MAX];
extern u16 gesture_coordinates_y[GESTURE_COORDS_REPORT_MAX];
extern int gesture_coords_reported;
extern struct mutex gestureMask_mutex;
#endif
struct fts_i2c_platform_data {
bool x_flip;
bool y_flip;
int (*power)(bool on);
int irq_gpio;
int reset_gpio;
const char *pwr_reg_name;
const char *bus_reg_name;
bool pwr_on_suspend;
};
/*
* Forward declaration
*/
struct fts_ts_info;
/*
* Dispatch event handler
*/
struct event_dispatch_handler_t {
void (*handler)(struct fts_ts_info *info, unsigned char *data);
};
/*
* struct fts_ts_info - FTS capacitive touch screen device information
* @dev: Pointer to the structure device
* @client: I2C client structure
* @input_dev Input device structure
* @work Work thread
* @event_wq Event queue for work thread
* @event_dispatch_table Event dispatch table handlers
* @attrs SysFS attributes
* @mode Device operating mode (bitmask)
* @touch_id Bitmask for touch id (mapped to input slots)
* @stylus_id Bitmask for tracking the stylus touches
* (mapped using the touchId)
* @timer Timer when operating in polling mode
* @power Power on/off routine
* @bdata HW info retrived from device tree
* @pwr_reg DVDD power regulator
* @bus_reg AVDD power regulator
* @resume_bit Indicate if screen off/on
* @fwupdate_stat Store the result of a fw update triggered by the host
* @notifier Used for be notified from a suspend/resume event
* @sensor_sleep true susped was called, false resume was called
* @wakelock Wake Lock struct
* @input_report_mutex mutex for handling the pressure of keys
* @series of switches to store the enabling status of a particular
* feature from the host
*/
struct fts_ts_info {
struct device *dev;
struct i2c_client *client;
struct input_dev *input_dev;
struct work_struct work;
struct work_struct suspend_work;
struct work_struct resume_work;
struct workqueue_struct *event_wq;
struct delayed_work fwu_work;
struct workqueue_struct *fwu_workqueue;
struct completion cmd_done;
struct pinctrl *ts_pinctrl;
struct pinctrl_state *pinctrl_state_active;
struct pinctrl_state *pinctrl_state_suspend;
struct pinctrl_state *pinctrl_state_release;
struct event_dispatch_handler_t *event_dispatch_table;
struct attribute_group attrs;
unsigned int mode;
unsigned long touch_id;
#ifdef STYLUS_MODE
unsigned long stylus_id;
#endif
#ifdef FTS_USE_POLLING_MODE
struct hrtimer timer;
#endif
#ifdef SCRIPTLESS
/*I2C cmd*/
struct device *i2c_cmd_dev;
char cmd_read_result[CMD_RESULT_STR_LEN];
char cmd_wr_result[CMD_RESULT_STR_LEN];
char cmd_write_result[20];
#endif
#ifdef DRIVER_TEST
struct device *test_cmd_dev;
#endif
int (*power)(bool on);
struct fts_i2c_platform_data *bdata;
struct regulator *pwr_reg;
struct regulator *bus_reg;
int resume_bit;
int fwupdate_stat;
struct notifier_block notifier;
bool sensor_sleep;
struct wakeup_source *wakeup_source;
/* input lock */
struct mutex input_report_mutex;
/*switches for features*/
unsigned int gesture_enabled;
unsigned int glove_enabled;
unsigned int charger_enabled;
unsigned int stylus_enabled;
unsigned int vr_enabled;
unsigned int cover_enabled;
unsigned int edge_rej_enabled;
unsigned int corner_rej_enabled;
unsigned int edge_palm_rej_enabled;
uint8_t *i2c_data;
uint8_t i2c_data_len;
struct device *aoi_cmd_dev;
bool aoi_notify_enabled;
bool aoi_wake_on_suspend;
/* aoi region */
int aoi_left;
int aoi_top;
int aoi_bottom;
int aoi_right;
};
extern struct chipInfo ftsInfo;
int fts_chip_powercycle(struct fts_ts_info *info);
int fts_chip_powercycle2(struct fts_ts_info *info, unsigned long sleep);
/*int fts_get_fw_version(struct fts_ts_info *info);*/
/*extern unsigned int le_to_uint(const unsigned char *ptr);*/
/*extern unsigned int be_to_uint(const unsigned char *ptr);*/
extern int input_register_notifier_client(struct notifier_block *nb);
extern int input_unregister_notifier_client(struct notifier_block *nb);
extern struct attribute_group aoi_cmd_attr_group;
#ifdef SCRIPTLESS
extern struct attribute_group i2c_cmd_attr_group;
#endif
#ifdef DRIVER_TEST
extern struct attribute_group test_cmd_attr_group;
#endif
#endif

View file

@ -0,0 +1,102 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
*/
#include <linux/device.h>
#include <linux/i2c.h>
#include "fts.h"
static ssize_t touch_event_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return 0;
}
ssize_t aoi_set_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
int left, top, right, bottom;
ret = sscanf(buf, "%d %d %d %d", &left, &top, &right, &bottom);
if (ret != 4)
return -EINVAL;
if (right > X_AXIS_MAX)
right = X_AXIS_MAX;
if (bottom > Y_AXIS_MAX)
bottom = Y_AXIS_MAX;
if (left < 0 || left > X_AXIS_MAX || right < 0 ||
top > Y_AXIS_MAX || bottom < 0)
return -EINVAL;
if (left >= right || top >= bottom) {
info->aoi_left = 0;
info->aoi_top = 0;
info->aoi_right = 0;
info->aoi_bottom = 0;
info->aoi_notify_enabled = false;
return count;
}
info->aoi_left = left;
info->aoi_top = top;
info->aoi_right = right;
info->aoi_bottom = bottom;
info->aoi_notify_enabled = true;
return count;
}
static ssize_t aoi_set_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
size_t len = 0;
len = scnprintf(buf + len, PAGE_SIZE,
"%d %d %d %d",
info->aoi_left,
info->aoi_top,
info->aoi_right,
info->aoi_bottom);
return len;
}
static ssize_t power_set_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int enable;
if (kstrtoint(buf, 10, &enable))
return -EINVAL;
return count;
}
static DEVICE_ATTR_RO(touch_event);
static DEVICE_ATTR_RW(aoi_set);
static DEVICE_ATTR_WO(power_set);
static struct attribute *aoi_cmd_attributes[] = {
&dev_attr_touch_event.attr,
&dev_attr_aoi_set.attr,
&dev_attr_power_set.attr,
NULL,
};
struct attribute_group aoi_cmd_attr_group = {
.attrs = aoi_cmd_attributes,
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,412 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/completion.h>
//#include <linux/wakelock.h>
#include <linux/pm_wakeup.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include "fts.h"
#include "fts_lib/ftsIO.h"
#ifdef SCRIPTLESS
static unsigned int fts_data[CMD_RESULT_STR_LEN] = {0};
static unsigned char fts_pAddress_i2c[CMD_RESULT_STR_LEN] = {0};
static int byte_count_read;
static char Out_buff[TSP_BUF_SIZE];
/*I2C CMd functions: functions to interface with GUI without script */
ssize_t fts_i2c_wr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
int i;
char buff[16];
memset(Out_buff, 0x00, sizeof(Out_buff));
if (byte_count_read == 0) {
snprintf(Out_buff, sizeof(Out_buff), "{FAILED}\n");
return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
}
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:DATA READ {\n", __func__);
for (i = 0; i < byte_count_read; i++) {
pr_err(" %02X\n", (unsigned int)info->cmd_wr_result[i]);
if (i < (byte_count_read - 1))
pr_err("\n");
}
pr_err("}\n");
#endif
snprintf(buff, sizeof(buff), "{");
strlcat(Out_buff, buff, sizeof(Out_buff));
for (i = 0; i < (byte_count_read + 2); i++) {
char temp_byte_count_read;
if (i == 0) {
temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
snprintf(buff, sizeof(buff), "%02X",
temp_byte_count_read);
} else if (i == 1) {
temp_byte_count_read = (byte_count_read) & 0xFF;
snprintf(buff, sizeof(buff), "%02X",
temp_byte_count_read);
} else {
snprintf(buff, sizeof(buff), "%02X",
info->cmd_wr_result[i-2]);
}
//snprintf(buff, sizeof(buff), "%02X", info->cmd_wr_result[i]);
strlcat(Out_buff, buff, sizeof(Out_buff));
if (i < (byte_count_read + 1)) {
snprintf(buff, sizeof(buff), " ");
strlcat(Out_buff, buff, sizeof(Out_buff));
}
}
snprintf(buff, sizeof(buff), "}");
strlcat(Out_buff, buff, sizeof(Out_buff));
return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
}
ssize_t fts_i2c_wr_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
unsigned char pAddress[9];
unsigned int byte_count = 0;
int i;
unsigned int data[9];
memset(data, 0x00, sizeof(data));
memset(pAddress, 0x00, sizeof(pAddress));
memset(info->cmd_wr_result, 0x00, CMD_RESULT_STR_LEN);
ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x ",
(data + 8), (data), (data + 1), (data + 2), (data + 3),
(data + 4), (data + 5), (data + 6), (data + 7));
byte_count = data[8];
/**
* if(sizeof(buf) != byte_count )
* {
* printk("%s : Byte count is wrong\n",__func__);
* return count;
* }
*/
if (byte_count > sizeof(pAddress))
return -EINVAL;
#ifdef SCRIPTLESS_DEBUG
pr_err("%s: Input Data 1:\n", __func__);
for (i = 0 ; i < byte_count; i++) {
pr_err(" %02X\n", data[i]);
pAddress[i] = (unsigned char)data[i];
}
pr_err("\n");
#else
for (i = 0 ; i < byte_count; i++)
pAddress[i] = (unsigned char)data[i];
#endif
byte_count_read = (((unsigned int)data[byte_count - 2]) << 8)
| data[byte_count - 1];
ret = fts_writeCmd(pAddress, 3);
msleep(20);
ret = fts_readCmd(&pAddress[3], (byte_count - 5),
info->cmd_wr_result, byte_count_read);
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:DATA READ {\n", __func__);
for (i = 0; i < (2 + byte_count_read); i++) {
char temp_byte_count_read;
if (i == 0) {
temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
pr_err("%02X\n", (unsigned int)temp_byte_count_read);
} else if (i == 1) {
temp_byte_count_read = (byte_count_read) & 0xFF;
pr_err("%02X\n", (unsigned int)temp_byte_count_read);
} else {
pr_err("%02X\n",
(unsigned int)info->cmd_read_result[i - 2]);
}
if (i < (byte_count_read + 1))
pr_err("\n");
}
pr_err("}\n");
#endif
if (ret)
dev_err(dev, "Unable to read register\n");
return count;
}
ssize_t fts_i2c_read_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
int i;
char buff[16];
memset(Out_buff, 0x00, sizeof(Out_buff));
if (byte_count_read == 0) {
snprintf(Out_buff, sizeof(Out_buff), "{FAILED}");
return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
}
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:DATA READ {\n", __func__);
for (i = 0; i < byte_count_read; i++) {
pr_err("%02X\n", (unsigned int)info->cmd_read_result[i]);
if (i < (byte_count_read - 1))
pr_err("\n");
}
pr_err("}\n");
#endif
snprintf(buff, sizeof(buff), "{");
strlcat(Out_buff, buff, sizeof(Out_buff));
for (i = 0; i < (byte_count_read + 2); i++) {
char temp_byte_count_read;
if (i == 0) {
temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
snprintf(buff, sizeof(buff), "%02X",
temp_byte_count_read);
} else if (i == 1) {
temp_byte_count_read = (byte_count_read) & 0xFF;
snprintf(buff, sizeof(buff), "%02X",
temp_byte_count_read);
} else {
snprintf(buff, sizeof(buff), "%02X",
info->cmd_read_result[i - 2]);
}
strlcat(Out_buff, buff, sizeof(Out_buff));
if (i < (byte_count_read + 1)) {
snprintf(buff, sizeof(buff), " ");
strlcat(Out_buff, buff, sizeof(Out_buff));
}
}
snprintf(buff, sizeof(buff), "}");
strlcat(Out_buff, buff, sizeof(Out_buff));
return snprintf(buf, TSP_BUF_SIZE, "%s\n", Out_buff);
}
ssize_t fts_i2c_read_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
unsigned char pAddress[9];
unsigned int byte_count = 0;
int i;
unsigned int data[9];
byte_count_read = 0;
memset(data, 0x00, sizeof(data));
memset(pAddress, 0x00, sizeof(pAddress));
memset(info->cmd_read_result, 0x00, CMD_RESULT_STR_LEN);
ret = sscanf(buf, "%x %x %x %x %x %x %x %x %x ",
(data + 8), (data), (data + 1), (data + 2), (data + 3),
(data + 4), (data + 5), (data + 6), (data + 7));
byte_count = data[8];
if (byte_count > 8) {
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:Byte count is more than 8\n", __func__);
#endif
return count;
}
/*if(sizeof(buf) != byte_count )*/
/*{*/
/* printk("%s : Byte count is wrong\n",__func__);*/
/* return count;*/
/*}*/
#ifdef SCRIPTLESS_DEBUG
pr_err("%s: Input Data 1:\n", __func__);
for (i = 0 ; i < byte_count; i++) {
pr_err("%02X\n", data[i]);
pAddress[i] = (unsigned char)data[i];
}
pr_err("\n");
#else
for (i = 0 ; i < byte_count; i++)
pAddress[i] = (unsigned char)data[i];
#endif
byte_count_read = (((unsigned int)data[byte_count - 2]) << 8)
| data[byte_count - 1];
ret = fts_readCmd(pAddress, (byte_count - 2), info->cmd_read_result,
byte_count_read);
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:DATA READ\n{\n", __func__);
for (i = 0; i < (byte_count_read + 2); i++) {
char temp_byte_count_read;
if (i == 0) {
temp_byte_count_read = (byte_count_read >> 8) & 0xFF;
pr_err("%02X\n", (unsigned int)temp_byte_count_read);
} else if (i == 1) {
temp_byte_count_read = (byte_count_read) & 0xFF;
pr_err("%02X\n", (unsigned int)temp_byte_count_read);
} else {
pr_err("%02X\n",
(unsigned int)info->cmd_read_result[i - 2]);
}
if (i < (byte_count_read + 1))
pr_err("\n");
}
pr_err("}\n");
#endif
if (ret)
dev_err(dev, "Unable to read register\n");
return count;
}
ssize_t fts_i2c_write_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
return snprintf(buf, TSP_BUF_SIZE, "%s", info->cmd_write_result);
}
ssize_t fts_i2c_write_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int ret;
struct i2c_client *client = to_i2c_client(dev);
struct fts_ts_info *info = i2c_get_clientdata(client);
unsigned int byte_count = 0;
int i;
unsigned int *data = &fts_data[0];
memset(fts_data, 0x00, sizeof(fts_data));
memset(fts_pAddress_i2c, 0x00, sizeof(fts_pAddress_i2c));
memset(info->cmd_write_result, 0x00, sizeof(info->cmd_write_result));
ret = sscanf(buf, "%x %x", data, (data + 1));
if (ret != 2)
return -EINVAL;
byte_count = data[0] << 8 | data[1];
if (byte_count <= sizeof(fts_pAddress_i2c)) {
for (i = 0; i < (byte_count); i++) {
ret = sscanf(&buf[3 * (i + 2)], "%x ", (data + i));
if (ret != 1)
return -EINVAL;
}
} else {
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:message size is > allowed limit of 512 bytes\n",
__func__);
#endif
snprintf(info->cmd_write_result, sizeof(info->cmd_write_result),
"{Write NOT OK}\n");
return -EINVAL;
}
#ifdef SCRIPTLESS_DEBUG
pr_err("\n");
pr_err("%s:Byte_count = %02d|Count = %02d |size of buf:%02d\n",
__func__, byte_count, (int)count, (int)sizeof(buf));
pr_err("%s: Input Data 1:\n", __func__);
for (i = 0 ; i < byte_count; i++) {
pr_err(" %02X\n", data[i]);
fts_pAddress_i2c[i] = (unsigned char)data[i];
}
pr_err("\n");
#else
for (i = 0 ; i < byte_count; i++)
fts_pAddress_i2c[i] = (unsigned char)data[i];
#endif
if ((fts_pAddress_i2c[0] == 0xb3) && (fts_pAddress_i2c[3] == 0xb1)) {
ret = fts_writeCmd(fts_pAddress_i2c, 3);
msleep(20);
ret = fts_writeCmd(&fts_pAddress_i2c[3], byte_count-3);
} else
ret = fts_writeCmd(fts_pAddress_i2c, byte_count);
#ifdef SCRIPTLESS_DEBUG
pr_err("%s:DATA :\n", __func__);
for (i = 0; i < byte_count; i++)
pr_err(" %02X\n", (unsigned int)fts_pAddress_i2c[i]);
pr_err(" byte_count: %02X\n", byte_count);
#endif
if (ret < 0) {
dev_err(dev, "{Write NOT OK}\n");
snprintf(info->cmd_write_result, sizeof(info->cmd_write_result),
"{Write NOT OK}\n");
} else {
snprintf(info->cmd_write_result, sizeof(info->cmd_write_result),
"{Write OK}\n");
#ifdef SCRIPTLESS_DEBUG
pr_err("%s : {Write OK}\n", __func__);
#endif
}
return count;
}
static DEVICE_ATTR_RW(fts_i2c_read);
static DEVICE_ATTR_RW(fts_i2c_wr);
static DEVICE_ATTR_RW(fts_i2c_write);
static struct attribute *i2c_cmd_attributes[] = {
&dev_attr_fts_i2c_read.attr,
&dev_attr_fts_i2c_wr.attr,
&dev_attr_fts_i2c_write.attr,
NULL,
};
struct attribute_group i2c_cmd_attr_group = {
.attrs = i2c_cmd_attributes,
};
#endif

View file

@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the FTS touchscreen driver.
#
obj-$(CONFIG_TOUCHSCREEN_ST) += ftsCompensation.o \
ftsCrossCompile.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o \
ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o

View file

@ -0,0 +1,744 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting Initialization Data *
* *
**************************************************************************
**************************************************************************
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
//#include <linux/sec_sysfs.h>
#include "ftsCrossCompile.h"
#include "ftsCompensation.h"
#include "ftsError.h"
#include "ftsFrame.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsSoftware.h"
#include "ftsTool.h"
static char tag[8] = "[ FTS ]\0";
struct chipInfo ftsInfo;
int requestCompensationData(u16 type)
{
int retry = 0;
int ret;
char *temp = NULL;
u16 answer;
int event_to_search[3];
u8 readEvent[FIFO_EVENT_SIZE];
u8 cmd[3] = { FTS_CMD_REQU_COMP_DATA, 0x00, 0x00};
/* B8 is the command for asking compensation data*/
u16ToU8(type, &cmd[1]);
event_to_search[0] = (int)EVENTID_COMP_DATA_READ;
event_to_search[1] = cmd[1];
event_to_search[2] = cmd[2];
while (retry < COMP_DATA_READ_RETRY) {
temp = printHex("Command = ", cmd, 3);
if (temp != NULL)
logError(0, "%s %s", tag, temp);
kfree(temp);
ret = fts_writeFwCmd(cmd, 3);
/*send the request to the chip to load*/
/*in memory the Compensation Data*/
if (ret < OK) {
logError(1, "%s %s:ERROR %02X\n",
tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
}
ret = pollForEvent(event_to_search, 3, readEvent,
TIMEOUT_REQU_COMP_DATA);
if (ret < OK) {
logError(0, "%s Event did not Found at %d attemp!\n",
tag, retry + 1);
retry += 1;
} else {
retry = 0;
break;
}
}
if (retry == COMP_DATA_READ_RETRY) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_TIMEOUT);
return ERROR_TIMEOUT;
}
u8ToU16_le(&readEvent[1], &answer);
if (answer == type)
return OK;
logError(1, "%sThe event found has a different type of ", tag);
logError(1, "Compensation data %02X\n", ERROR_DIFF_COMP_TYPE);
return ERROR_DIFF_COMP_TYPE;
}
int readCompensationDataHeader(u16 type, struct DataHeader *header,
u16 *address)
{
u16 offset = ADDR_FRAMEBUFFER_DATA;
u16 answer;
u8 data[COMP_DATA_HEADER];
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data, COMP_DATA_HEADER,
DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
logError(0, "%s Read Data Header done!\n", tag);
if (data[0] != HEADER_SIGNATURE) {
logError(1, "%s %s:%02X The Header Signature was wrong!",
tag, __func__, ERROR_WRONG_COMP_SIGN);
logError(1, "%02X != %02X\n", data[0], HEADER_SIGNATURE);
return ERROR_WRONG_COMP_SIGN;
}
u8ToU16_le(&data[1], &answer);
if (answer != type) {
logError(1, "%s %s:ERROR %02X\n",
tag, __func__, ERROR_DIFF_COMP_TYPE);
return ERROR_DIFF_COMP_TYPE;
}
logError(0, "%s Type of Compensation data OK!\n", tag);
header->type = type;
header->force_node = (int)data[4];
header->sense_node = (int)data[5];
*address = offset + COMP_DATA_HEADER;
return OK;
}
int readMutualSenseGlobalData(u16 *address, struct MutualSenseData *global)
{
u8 data[COMP_DATA_GLOBAL];
logError(0, "%s Address for Global data= %02X\n", tag, *address);
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
logError(0, "%s Global data Read!\n", tag);
global->tuning_ver = data[0];
global->cx1 = data[1];
logError(0, "%s tuning_ver = %d CX1 = %d\n",
tag, global->tuning_ver, global->cx1);
*address += COMP_DATA_GLOBAL;
return OK;
}
int readMutualSenseNodeData(u16 address, struct MutualSenseData *node)
{
int size = node->header.force_node*node->header.sense_node;
logError(0, "%s Address for Node data = %02X\n", tag, address);
node->node_data = (u8 *)kmalloc_array(size, (sizeof(u8)), GFP_KERNEL);
if (node->node_data == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
logError(0, "%s Node Data to read %d bytes\n", tag, size);
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, node->node_data,
size, DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s:ERROR %02X\n", tag, __func__, ERROR_I2C_R);
kfree(node->node_data);
return ERROR_I2C_R;
}
node->node_data_size = size;
logError(0, "%s Read node data ok!\n", tag);
return size;
}
int readMutualSenseCompensationData(u16 type, struct MutualSenseData *data)
{
int ret;
u16 address;
data->node_data = NULL;
if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER
|| type == MS_TOUCH_ULTRA_LOW_POWER || type == MS_KEY)) {
logError(1, "%s %s: Choose a MS type of compensation data ",
tag, __func__);
logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_REQU_COMP_DATA);
return (ret|ERROR_REQU_COMP_DATA);
}
ret = readCompensationDataHeader(type, &(data->header), &address);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_HEADER);
return (ret | ERROR_COMP_DATA_HEADER);
}
ret = readMutualSenseGlobalData(&address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_GLOBAL);
return (ret|ERROR_COMP_DATA_GLOBAL);
}
ret = readMutualSenseNodeData(address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_NODE);
return (ret | ERROR_COMP_DATA_NODE);
}
return OK;
}
int readSelfSenseGlobalData(u16 *address, struct SelfSenseData *global)
{
u8 data[COMP_DATA_GLOBAL];
logError(0, "%s Address for Global data= %02X\n", tag, *address);
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
logError(0, "%s Global data Read!\n", tag);
global->tuning_ver = data[0];
global->f_ix1 = data[1];
global->s_ix1 = data[2];
global->f_cx1 = data[3];
global->s_cx1 = data[4];
global->f_max_n = data[5];
global->s_max_n = data[6];
logError(0,
"%stuning_ver = %df_ix1 = %ds_ix1 = %df_cx1 = %d s_cx1 = %d\n",
tag, global->tuning_ver, global->f_ix1,
global->s_ix1, global->f_cx1, global->s_cx1);
logError(0, "%s max_n = %d s_max_n = %d\n",
tag, global->f_max_n, global->s_max_n);
*address += COMP_DATA_GLOBAL;
return OK;
}
int readSelfSenseNodeData(u16 address, struct SelfSenseData *node)
{
int size = node->header.force_node * 2 + node->header.sense_node * 2;
u8 *data;
node->ix2_fm = (u8 *)kmalloc_array(node->header.force_node,
sizeof(u8), GFP_KERNEL);
if (node->ix2_fm == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
node->cx2_fm = (u8 *)kmalloc_array(node->header.force_node,
sizeof(u8), GFP_KERNEL);
if (node->cx2_fm == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
kfree(node->ix2_fm);
return ERROR_ALLOC;
}
node->ix2_sn = (u8 *)kmalloc_array(node->header.sense_node,
sizeof(u8), GFP_KERNEL);
if (node->ix2_sn == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
return ERROR_ALLOC;
}
node->cx2_sn = (u8 *)kmalloc_array(node->header.sense_node,
sizeof(u8), GFP_KERNEL);
if (node->cx2_sn == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
kfree(node->ix2_sn);
return ERROR_ALLOC;
}
logError(0, "%s Address for Node data = %02X\n", tag, address);
logError(0, "%s Node Data to read %d bytes\n", tag, size);
data = (u8 *)kmalloc_array(size, sizeof(u8), GFP_KERNEL);
if (data == NULL) {
logError(1, "%s %s: ERROR %02X", tag, __func__, ERROR_ALLOC);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
kfree(node->ix2_sn);
kfree(node->cx2_sn);
return ERROR_ALLOC;
}
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, size,
DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
kfree(node->ix2_sn);
kfree(node->cx2_sn);
kfree(data);
return ERROR_I2C_R;
}
logError(0, "%s Read node data ok!\n", tag);
memcpy(node->ix2_fm, data, node->header.force_node);
memcpy(node->ix2_sn, &data[node->header.force_node],
node->header.sense_node);
memcpy(node->cx2_fm,
&data[node->header.force_node + node->header.sense_node],
node->header.force_node);
memcpy(node->cx2_sn,
&data[node->header.force_node * 2 + node->header.sense_node],
node->header.sense_node);
kfree(data);
return OK;
}
int readSelfSenseCompensationData(u16 type, struct SelfSenseData *data)
{
int ret;
u16 address;
data->ix2_fm = NULL;
data->cx2_fm = NULL;
data->ix2_sn = NULL;
data->cx2_sn = NULL;
if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER
|| type == SS_PROXIMITY)) {
logError(1, "%s %s:Choose a SS type of compensation data ",
tag, __func__);
logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_REQU_COMP_DATA);
return (ret | ERROR_REQU_COMP_DATA);
}
ret = readCompensationDataHeader(type, &(data->header), &address);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_HEADER);
return (ret|ERROR_COMP_DATA_HEADER);
}
ret = readSelfSenseGlobalData(&address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_GLOBAL);
return (ret | ERROR_COMP_DATA_GLOBAL);
}
ret = readSelfSenseNodeData(address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_NODE);
return (ret | ERROR_COMP_DATA_NODE);
}
return OK;
}
int readGeneralGlobalData(u16 address, struct GeneralData *global)
{
u8 data[COMP_DATA_GLOBAL];
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, address, data, COMP_DATA_GLOBAL,
DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
global->ftsd_lp_timer_cal0 = data[0];
global->ftsd_lp_timer_cal1 = data[1];
global->ftsd_lp_timer_cal2 = data[2];
global->ftsd_lp_timer_cal3 = data[3];
global->ftsa_lp_timer_cal0 = data[4];
global->ftsa_lp_timer_cal1 = data[5];
return OK;
}
int readGeneralCompensationData(u16 type, struct GeneralData *data)
{
int ret;
u16 address;
if (!(type == GENERAL_TUNING)) {
logError(1, "%s %s:Choose a GENERAL type of compensation data ",
tag);
logError(1, "ERROR %02X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_REQU_COMP_DATA);
return ERROR_REQU_COMP_DATA;
}
ret = readCompensationDataHeader(type, &(data->header), &address);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_HEADER);
return ERROR_COMP_DATA_HEADER;
}
ret = readGeneralGlobalData(address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_GLOBAL);
return ERROR_COMP_DATA_GLOBAL;
}
return OK;
}
int defaultChipInfo(int i2cError)
{
int i;
logError(0, "%s Setting default Chip Info...\n", tag);
ftsInfo.u32_echoEn = 0x00000000;
ftsInfo.u8_msScrConfigTuneVer = 0;
ftsInfo.u8_ssTchConfigTuneVer = 0;
ftsInfo.u8_msScrCxmemTuneVer = 0;
ftsInfo.u8_ssTchCxmemTuneVer = 0;
if (i2cError == 1) {
ftsInfo.u16_fwVer = 0xFFFF;
ftsInfo.u16_cfgId = 0xFFFF;
for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++)
ftsInfo.u8_extReleaseInfo[i] = 0xFF;
} else {
ftsInfo.u16_fwVer = 0x0000;
ftsInfo.u16_cfgId = 0x0000;
for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++)
ftsInfo.u8_extReleaseInfo[i] = 0x00;
}
ftsInfo.u32_mpPassFlag = INIT_FIELD;
ftsInfo.u16_errOffset = INVALID_ERROR_OFFS;
logError(0, "%s default Chip Info DONE!\n", tag);
return OK;
}
int readChipInfo(int doRequest)
{
int ret, i;
u16 answer;
u8 data[CHIP_INFO_SIZE + 3];
/*+3 because need to read all the field of*/
/*the struct plus the signature and 2 address bytes*/
int index = 0;
logError(0, "%s Starting Read Chip Info...\n", tag);
if (doRequest == 1) {
ret = requestCompensationData(CHIP_INFO);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_REQU_COMP_DATA);
ret = (ret | ERROR_REQU_COMP_DATA);
goto FAIL;
}
}
logError(0, "%s Byte to read = %d bytes\n", tag, CHIP_INFO_SIZE + 3);
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, ADDR_FRAMEBUFFER_DATA, data,
CHIP_INFO_SIZE + 3, DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
ret = ERROR_I2C_R;
goto FAIL;
}
logError(0, "%s Read data ok!\n", tag);
logError(0, "%s Starting parsing of data...\n", tag);
if (data[0] != HEADER_SIGNATURE) {
logError(1, "%s %s:ERROR ", tag, __func__);
logError(1, "%02X The Header Signature is wrong!%02X != %02X\n",
ERROR_WRONG_COMP_SIGN, data[0], HEADER_SIGNATURE);
ret = ERROR_WRONG_COMP_SIGN;
goto FAIL;
}
u8ToU16_le(&data[1], &answer);
if (answer != CHIP_INFO) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_DIFF_COMP_TYPE);
ret = ERROR_DIFF_COMP_TYPE;
goto FAIL;
}
index += 3;
ftsInfo.u8_loadCnt = data[index++];
ftsInfo.u8_infoVer = data[index++];
u8ToU16(&data[index], &ftsInfo.u16_ftsdId);
index += 2;
ftsInfo.u8_ftsdVer = data[index++];
ftsInfo.u8_ftsaId = data[index++];
ftsInfo.u8_ftsaVer = data[index++];
ftsInfo.u8_tchRptVer = data[index++];
logError(0, "%s External Release = ", tag);
for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) {
ftsInfo.u8_extReleaseInfo[i] = data[index++];
logError(0, "%02X ", ftsInfo.u8_extReleaseInfo[i]);
}
logError(0, "\n");
for (i = 0; i < sizeof(ftsInfo.u8_custInfo); i++)
ftsInfo.u8_custInfo[i] = data[index++];
u8ToU16(&data[index], &ftsInfo.u16_fwVer);
index += 2;
logError(1, "%s FW VERSION = %04X\n", tag, ftsInfo.u16_fwVer);
u8ToU16(&data[index], &ftsInfo.u16_cfgId);
index += 2;
logError(1, "%s CONFIG ID = %04X\n", tag, ftsInfo.u16_cfgId);
ftsInfo.u32_projId = ((data[index + 3] & 0x000000FF) << 24) +
((data[index + 2] & 0x000000FF) << 16) +
((data[index + 1] & 0x000000FF) << 8) +
(data[index] & 0x000000FF);
index += 4;
u8ToU16(&data[index], &ftsInfo.u16_scrXRes);
index += 2;
u8ToU16(&data[index], &ftsInfo.u16_scrYRes);
index += 2;
ftsInfo.u8_scrForceLen = data[index++];
logError(0, "%s Force Len = %d\n", tag, ftsInfo.u8_scrForceLen);
ftsInfo.u8_scrSenseLen = data[index++];
logError(0, "%s Sense Len = %d\n", tag, ftsInfo.u8_scrSenseLen);
for (i = 0; i < 8; i++)
ftsInfo.u64_scrForceEn[i] = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_scrSenseEn[i] = data[index++];
ftsInfo.u8_msKeyLen = data[index++];
logError(0, "%s MS Key Len = %d\n", tag, ftsInfo.u8_msKeyLen);
for (i = 0; i < 8; i++)
ftsInfo.u64_msKeyForceEn[i] = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_msKeySenseEn[i] = data[index++];
ftsInfo.u8_ssKeyLen = data[index++];
logError(0, "%s SS Key Len = %d\n", tag, ftsInfo.u8_ssKeyLen);
for (i = 0; i < 8; i++)
ftsInfo.u64_ssKeyForceEn[i] = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_ssKeySenseEn[i] = data[index++];
ftsInfo.u8_frcTchXLen = data[index++];
ftsInfo.u8_frcTchYLen = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_frcTchForceEn[i] = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_frcTchSenseEn[i] = data[index++];
ftsInfo.u8_msScrConfigTuneVer = data[index++];
logError(0, "%s CFG MS TUNING VERSION = %02X\n",
tag, ftsInfo.u8_msScrConfigTuneVer);
ftsInfo.u8_msScrLpConfigTuneVer = data[index++];
ftsInfo.u8_msScrHwulpConfigTuneVer = data[index++];
ftsInfo.u8_msKeyConfigTuneVer = data[index++];
ftsInfo.u8_ssTchConfigTuneVer = data[index++];
logError(0, "%s CFG SS TUNING VERSION = %02X\n",
tag, ftsInfo.u8_ssTchConfigTuneVer);
ftsInfo.u8_ssKeyConfigTuneVer = data[index++];
ftsInfo.u8_ssHvrConfigTuneVer = data[index++];
ftsInfo.u8_frcTchConfigTuneVer = data[index++];
ftsInfo.u8_msScrCxmemTuneVer = data[index++];
logError(0, "%s CX MS TUNING VERSION = %02X\n",
tag, ftsInfo.u8_msScrCxmemTuneVer);
ftsInfo.u8_msScrLpCxmemTuneVer = data[index++];
ftsInfo.u8_msScrHwulpCxmemTuneVer = data[index++];
ftsInfo.u8_msKeyCxmemTuneVer = data[index++];
ftsInfo.u8_ssTchCxmemTuneVer = data[index++];
logError(0, "%s CX SS TUNING VERSION = %02X\n",
tag, ftsInfo.u8_ssTchCxmemTuneVer);
ftsInfo.u8_ssKeyCxmemTuneVer = data[index++];
ftsInfo.u8_ssHvrCxmemTuneVer = data[index++];
ftsInfo.u8_frcTchCxmemTuneVer = data[index++];
ftsInfo.u32_mpPassFlag = ((data[index + 3] & 0x000000FF) << 24)
+ ((data[index + 2] & 0x000000FF) << 16) +
((data[index + 1] & 0x000000FF) << 8) +
(data[index] & 0x000000FF);
index += 4;
logError(0, "%s MP SIGNATURE = %08X\n", tag, ftsInfo.u32_mpPassFlag);
ftsInfo.u32_featEn = ((data[index + 3] & 0x000000FF) << 24) +
((data[index + 2] & 0x000000FF) << 16) +
((data[index + 1] & 0x000000FF) << 8) +
(data[index] & 0x000000FF);
index += 4;
ftsInfo.u32_echoEn = ((data[index + 3] & 0x000000FF) << 24) +
((data[index + 2] & 0x000000FF) << 16) +
((data[index + 1] & 0x000000FF) << 8) +
(data[index] & 0x000000FF);
index += 4;
logError(0, "%s FEATURES = %08X\n", tag, ftsInfo.u32_echoEn);
ftsInfo.u8_sideTchConfigTuneVer = data[index++];
ftsInfo.u8_sideTchCxmemTuneVer = data[index++];
ftsInfo.u8_sideTchForceLen = data[index++];
logError(0, "%s Side Touch Force Len = %d\n",
tag, ftsInfo.u8_sideTchForceLen);
ftsInfo.u8_sideTchSenseLen = data[index++];
logError(0, "%s Side Touch Sense Len = %d\n",
tag, ftsInfo.u8_sideTchSenseLen);
for (i = 0; i < 8; i++)
ftsInfo.u64_sideTchForceEn[i] = data[index++];
for (i = 0; i < 8; i++)
ftsInfo.u64_sideTchSenseEn[i] = data[index++];
ftsInfo.u8_errSign = data[index++];
logError(0, "%s ERROR SIGNATURE = %02X\n", tag, ftsInfo.u8_errSign);
if (ftsInfo.u8_errSign == ERROR_SIGN_HEAD) {
logError(0, "%s Correct Error Signature found!\n", tag);
u8ToU16(&data[index], &ftsInfo.u16_errOffset);
} else {
logError(1, "%s Error Signature NOT FOUND!\n", tag);
ftsInfo.u16_errOffset = INVALID_ERROR_OFFS;
}
logError(0, "%s ERROR OFFSET = %04X\n", tag, ftsInfo.u16_errOffset);
index += 2;
logError(0, "%s Parsed %d bytes!\n", tag, index);
if (index != CHIP_INFO_SIZE + 3) {
logError(1, "%s %s: index = %d different from %d ERROR %02X\n",
tag, __func__, index, CHIP_INFO_SIZE + 3,
ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
logError(0, "%s Chip Info Read DONE!\n", tag);
return OK;
FAIL:
defaultChipInfo(isI2cError(ret));
return ret;
}

View file

@ -0,0 +1,207 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS API for Flashing the IC *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_COMPENSATION_H
#define __FTS_COMPENSATION_H
#include "ftsCrossCompile.h"
#include "ftsSoftware.h"
#define COMP_DATA_READ_RETRY 2
//Bytes dimension of Compensation Data Format
#define COMP_DATA_HEADER 8
#define COMP_DATA_GLOBAL 8
#define HEADER_SIGNATURE 0xA5
#define INVALID_ERROR_OFFS 0xFFFF
//Possible Compensation/Frame Data Type
#define GENERAL_TUNING 0x0100
#define MS_TOUCH_ACTIVE 0x0200
#define MS_TOUCH_LOW_POWER 0x0400
#define MS_TOUCH_ULTRA_LOW_POWER 0x0800
#define MS_KEY 0x1000
#define SS_TOUCH 0x2000
#define SS_KEY 0x4000
#define SS_HOVER 0x8000
#define SS_PROXIMITY 0x0001
#define CHIP_INFO 0xFFFF
#define TIMEOUT_REQU_COMP_DATA 1000 //ms
//CHIP INFO
#define CHIP_INFO_SIZE 161
/*bytes to read from framebuffer (exclude the signature and the type*/
/*because already checked during the reading)*/
#define EXTERNAL_RELEASE_INFO_SIZE 8 //bytes
struct DataHeader {
int force_node, sense_node;
u16 type;
};
struct MutualSenseData {
struct DataHeader header;
u8 tuning_ver;
u8 cx1;
u8 *node_data;
int node_data_size;
};
struct SelfSenseData {
struct DataHeader header;
u8 tuning_ver;
u8 f_ix1, s_ix1;
u8 f_cx1, s_cx1;
u8 f_max_n, s_max_n;
u8 *ix2_fm;
u8 *ix2_sn;
u8 *cx2_fm;
u8 *cx2_sn;
};
struct GeneralData {
struct DataHeader header;
u8 ftsd_lp_timer_cal0;
u8 ftsd_lp_timer_cal1;
u8 ftsd_lp_timer_cal2;
u8 ftsd_lp_timer_cal3;
u8 ftsa_lp_timer_cal0;
u8 ftsa_lp_timer_cal1;
};
struct chipInfo {
u8 u8_loadCnt; ///< 03 - Load Counter
u8 u8_infoVer; ///< 04 - New chip info version
u16 u16_ftsdId; ///< 05 - FTSD ID
u8 u8_ftsdVer; ///< 07 - FTSD version
u8 u8_ftsaId; ///< 08 - FTSA ID
u8 u8_ftsaVer; ///< 09 - FTSA version
u8 u8_tchRptVer; ///< 0A - Touch report version (e.g. ST, Samsung etc)
///< 0B - External release information
u8 u8_extReleaseInfo[EXTERNAL_RELEASE_INFO_SIZE];
u8 u8_custInfo[12]; ///< 13 - Customer information
u16 u16_fwVer; ///< 1F - Firmware version
u16 u16_cfgId; ///< 21 - Configuration ID
u32 u32_projId; ///< 23 - Project ID
u16 u16_scrXRes; ///< 27 - X resolution on main screen
u16 u16_scrYRes; ///< 29 - Y resolution on main screen
u8 u8_scrForceLen; ///< 2B - Number of force channel on main screen
u8 u8_scrSenseLen; ///< 2C - Number of sense channel on main screen
u8 u64_scrForceEn[8]; ///< 2D - Force channel enabled on main screen
u8 u64_scrSenseEn[8]; ///< 35 - Sense channel enabled on main screen
u8 u8_msKeyLen; ///< 3D - Number of MS Key channel
u8 u64_msKeyForceEn[8]; ///< 3E - MS Key force channel enable
u8 u64_msKeySenseEn[8]; ///< 46 - MS Key sense channel enable
u8 u8_ssKeyLen; ///< 4E - Number of SS Key channel
u8 u64_ssKeyForceEn[8]; ///< 4F - SS Key force channel enable
u8 u64_ssKeySenseEn[8]; ///< 57 - SS Key sense channel enable
u8 u8_frcTchXLen; ///< 5F - Number of force touch force channel
u8 u8_frcTchYLen; ///< 60 - Number of force touch sense channel
u8 u64_frcTchForceEn[8];///< 61 - Force touch force channel enable
u8 u64_frcTchSenseEn[8];///< 69 - Force touch sense channel enable
u8 u8_msScrConfigTuneVer; ///< 71 - MS screen tuning version in config
///< 72 - MS screen LP mode tuning version in config
u8 u8_msScrLpConfigTuneVer;
///< 73 - MS screen ultra low power mode tuning version in config
u8 u8_msScrHwulpConfigTuneVer;
u8 u8_msKeyConfigTuneVer; ///< 74 - MS Key tuning version in config
u8 u8_ssTchConfigTuneVer; ///< 75 - SS touch tuning version in config
u8 u8_ssKeyConfigTuneVer; ///< 76 - SS Key tuning version in config
u8 u8_ssHvrConfigTuneVer; ///< 77 - SS hover tuning version in config
///< 78 - Force touch tuning version in config
u8 u8_frcTchConfigTuneVer;
u8 u8_msScrCxmemTuneVer; ///< 79 - MS screen tuning version in cxmem
///< 7A - MS screen LP mode tuning version in cxmem
u8 u8_msScrLpCxmemTuneVer;
///< 7B - MS screen ultra low power mode tuning version in cxmem
u8 u8_msScrHwulpCxmemTuneVer;
u8 u8_msKeyCxmemTuneVer; ///< 7C - MS Key tuning version in cxmem
u8 u8_ssTchCxmemTuneVer; ///< 7D - SS touch tuning version in cxmem
u8 u8_ssKeyCxmemTuneVer; ///< 7E - SS Key tuning version in cxmem
u8 u8_ssHvrCxmemTuneVer; ///< 7F - SS hover tuning version in cxmem
///< 80 - Force touch tuning version in cxmem
u8 u8_frcTchCxmemTuneVer;
u32 u32_mpPassFlag; ///< 81 - Mass production pass flag
u32 u32_featEn; ///< 85 - Supported features
///< 89 - enable of particular features: first bit is Echo Enables
u32 u32_echoEn;
///< 8D - Side Touch tuning version in config
u8 u8_sideTchConfigTuneVer;
u8 u8_sideTchCxmemTuneVer; ///< 8E - Side Touch tuning version in cxmem
u8 u8_sideTchForceLen; ///< 8F - Number of force channel on side touch
u8 u8_sideTchSenseLen; ///< 90 - Number of sense channel on side touch
u8 u64_sideTchForceEn[8];///< 91 - Side touch force channel enable
u8 u64_sideTchSenseEn[8];///< 99 - Side touch sense channel enable
u8 u8_errSign; ///< A1 - Signature for error field
u16 u16_errOffset; ///< A2 - Error Offset
};
int requestCompensationData(u16 type);
int readCompensationDataHeader(u16 type, struct DataHeader *header,
u16 *address);
int readMutualSenseGlobalData(u16 *address, struct MutualSenseData *global);
int readMutualSenseNodeData(u16 address, struct MutualSenseData *node);
int readMutualSenseCompensationData(u16 type, struct MutualSenseData *data);
int readSelfSenseGlobalData(u16 *address, struct SelfSenseData *global);
int readSelfSenseNodeData(u16 address, struct SelfSenseData *node);
int readSelfSenseCompensationData(u16 type, struct SelfSenseData *data);
int readGeneralGlobalData(u16 address, struct GeneralData *global);
int readGeneralCompensationData(u16 type, struct GeneralData *data);
int defaultChipInfo(int i2cError);
int readChipInfo(int doRequest);
#endif

View file

@ -0,0 +1,77 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Cross Compile *
* *
**************************************************************************
**************************************************************************
*
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
//#include <linux/sec_sysfs.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <linux/fcntl.h>
#include <linux/syscalls.h>
#include "ftsCrossCompile.h"
#include "ftsError.h"
void *stmalloc(size_t size)
{
return kmalloc(size, GFP_KERNEL);
}
void stfree(void *ptr)
{
kfree(ptr);
}

View file

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2018, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS cross compile *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_CROSS_COMPILE_H
#define __FTS_CROSS_COMPILE_H
//#define NDK
//#define DEBUG
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
//#include <linux/sec_sysfs.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <linux/fcntl.h>
#include <linux/syscalls.h>
void *stmalloc(size_t size);
void stfree(void *ptr);
#endif

View file

@ -0,0 +1,262 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS error/info kernel log reporting *
* *
**************************************************************************
**************************************************************************
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/hrtimer.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/completion.h>
//#include <linux/wakelock.h>
#include <linux/pm_wakeup.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include "../fts.h"
#include "ftsCrossCompile.h"
#include "ftsError.h"
#include "ftsIO.h"
#include "ftsTool.h"
#include "ftsCompensation.h"
static char tag[8] = "[ FTS ]\0";
void logError(int force, const char *msg, ...)
{
if (force == 1
#ifdef DEBUG
|| 1
#endif
) {
va_list args;
va_start(args, msg);
vprintk(msg, args);
va_end(args);
}
}
int isI2cError(int error)
{
if (((error & 0x000000FF) >= (ERROR_I2C_R & 0x000000FF))
&& ((error & 0x000000FF) <= (ERROR_I2C_O & 0x000000FF)))
return 1;
else
return 0;
}
int dumpErrorInfo(void)
{
int ret, i;
u8 data[ERROR_INFO_SIZE] = {0};
u32 sign = 0;
logError(0, "%s %s: Starting dump of error info...\n", tag, __func__);
if (ftsInfo.u16_errOffset == INVALID_ERROR_OFFS) {
logError(1, "%s %s: Invalid error offset ERROR %02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, ftsInfo.u16_errOffset,
data, ERROR_INFO_SIZE, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: reading data ERROR %02X\n",
tag, __func__, ret);
return ret;
}
logError(0, "%s %s: Error Info =\n", tag, __func__);
u8ToU32(data, &sign);
if (sign != ERROR_SIGNATURE)
logError(1, "%s %s:Wrong Signature! Data may be invalid!\n",
tag, __func__);
else
logError(1, "%s %s: Error Signature OK! Data are valid!\n",
tag, __func__);
for (i = 0; i < ERROR_INFO_SIZE; i++) {
if (i % 4 == 0)
logError(1, KERN_ERR "\n%s %s: %d) ",
tag, __func__, i / 4);
logError(1, "%02X ", data[i]);
}
logError(1, "\n");
logError(0, "%s %s: dump of error info FINISHED!\n", tag, __func__);
return OK;
}
int errorHandler(u8 *event, int size)
{
int res = OK;
struct fts_ts_info *info = NULL;
if (getClient() != NULL)
info = i2c_get_clientdata(getClient());
if (info == NULL || event == NULL || size <= 1 || event[0] !=
EVENTID_ERROR_EVENT) {
logError(1, "%s %s: event Null or not correct size! ",
tag, __func__, ERROR_OP_NOT_ALLOW);
logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
logError(0, "%s %s: Starting handling...\n", tag, __func__);
//TODO: write an error log for undefinied command subtype 0xBA
switch (event[1]) {
case EVENT_TYPE_ESD_ERROR: //esd
res = fts_chip_powercycle(info);
if (res < OK) {
logError(1, "%s %s: ", tag, res);
logError(1, "Error performing powercycle ERROR %08X\n");
}
res = fts_system_reset();
if (res < OK)
logError(1, "%s %s:Cannot reset device ERROR%08X\n",
tag, __func__, res);
res = (ERROR_HANDLER_STOP_PROC | res);
break;
case EVENT_TYPE_WATCHDOG_ERROR: //watchdog
dumpErrorInfo();
res = fts_system_reset();
if (res < OK)
logError(1, "%s %s:Cannot reset device:ERROR%08X\n",
tag, __func__, res);
res = (ERROR_HANDLER_STOP_PROC | res);
break;
case EVENT_TYPE_CHECKSUM_ERROR: //CRC ERRORS
switch (event[2]) {
case CRC_CONFIG_SIGNATURE:
logError(1, "%s %s: Config Signature ERROR!\n",
tag, __func__);
break;
case CRC_CONFIG:
logError(1, "%s %s:Config CRC ERROR!\n", tag, __func__);
break;
case CRC_CX_MEMORY:
logError(1, "%s %s: CX CRC ERROR!\n", tag, __func__);
break;
}
break;
case EVENT_TYPE_LOCKDOWN_ERROR:
//res = (ERROR_HANDLER_STOP_PROC|res);
//stop lockdown code routines in order to retry
switch (event[2]) {
case 0x01:
logError(1, "%s %s:Lockdown code alredy ",
tag, __func__);
logError(1, "written into the IC!\n");
break;
case 0x02:
logError(1, "%s %s:Lockdown CRC ", tag, __func__);
logError(1, "check fail during a WRITE!\n");
break;
case 0x03:
logError(1,
"%s %s:Lockdown WRITE command format wrong!\n",
tag, __func__);
break;
case 0x04:
pr_err("Lockdown Memory Corrupted!\n");
logError(1, "%s %s:Please contact ST for support!\n",
tag, __func__);
break;
case 0x11:
logError(1,
"%s %s:NO Lockdown code to READ into the IC!\n",
tag, __func__);
break;
case 0x12:
logError(1,
"%s %s:Lockdown code data corrupted\n",
tag, __func__);
break;
case 0x13:
logError(1,
"%s %s:Lockdown READ command format wrong!\n",
tag, __func__);
break;
case 0x21:
pr_err("Exceeded maximum number of\n");
logError(1,
"%s %s:Lockdown code REWRITE into IC!\n",
tag, __func__);
break;
case 0x22:
logError(1, "%s %s:Lockdown CRC check", tag, __func__);
logError(1, " fail during a REWRITE!\n");
break;
case 0x23:
logError(1, "%s %s:", tag, __func__);
logError(1, "Lockdown REWRITE command format wrong!\n");
break;
case 0x24:
pr_err("Lockdown Memory Corrupted!\n");
logError(1, "%s %s:Please contact ST for support!\n",
tag, __func__);
break;
default:
logError(1, "%s %s:No valid error type for LOCKDOWN!\n",
tag, __func__);
}
break;
default:
logError(0, "%s %s: No Action taken!\n", tag, __func__);
break;
}
logError(0, "%s %s: handling Finished! res = %08X\n",
tag, __func__, res);
return res;
}

View file

@ -0,0 +1,181 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS error/info kernel log reporting *
* *
**************************************************************************
**************************************************************************
*/
#ifndef __FTS_ERROR_H
#define __FTS_ERROR_H
//FIRST LEVEL ERROR CODE
#define OK (int)(0x00000000)/* No ERROR*/
/*allocation of memory failed*/
#define ERROR_ALLOC (int)(0x80000001)
#define ERROR_I2C_R (int)(0x80000002)//i2c read failed
#define ERROR_I2C_W (int)(0x80000003)//i2c write failed
#define ERROR_I2C_WR (int)(0x80000004)//i2c write/read failed
//error during opening i2c device
#define ERROR_I2C_O (int)(0x80000005)
#define ERROR_OP_NOT_ALLOW (int)(0x80000006)//operation not allowed
//timeout expired! exceed the max number of
//retries or the max waiting time
#define ERROR_TIMEOUT (int)(0x80000007)
//the file that i want to open is not found
#define ERROR_FILE_NOT_FOUND (int)(0x80000008)
//error during parsing the file
#define ERROR_FILE_PARSE (int)(0x80000009)
//error during reading the file
#define ERROR_FILE_READ (int)(0x8000000A)
#define ERROR_LABEL_NOT_FOUND (int)(0x8000000B)//label not found
//fw in the chip newer than the one in the memmh
#define ERROR_FW_NO_UPDATE (int)(0x8000000C)
//flash status busy or unknown
#define ERROR_FLASH_UNKNOWN (int)(0x8000000D)
//SECOND LEVEL ERROR CODE
//unable to disable the interrupt
#define ERROR_DISABLE_INTER (int)(0x80000200)
//unable to activate the interrupt
#define ERROR_ENABLE_INTER (int)(0x80000300)
#define ERROR_READ_B2 (int)(0x80000400)//B2 command failed
//unable to read an offset from memory
#define ERROR_GET_OFFSET (int)(0x80000500)
//unable to retrieve the data of a required frame
#define ERROR_GET_FRAME_DATA (int)(0x80000600)
//FW answers with an event that has a
//different address respect the request done
#define ERROR_DIFF_COMP_TYPE (int)(0x80000700)
//the signature of the compensation data is not A5
#define ERROR_WRONG_COMP_SIGN (int)(0x80000800)
//the command Sense On failed
#define ERROR_SENSE_ON_FAIL (int)(0x80000900)
//the command Sense Off failed
#define ERROR_SENSE_OFF_FAIL (int)(0x80000A00)
//the command SYSTEM RESET failed
#define ERROR_SYSTEM_RESET_FAIL (int)(0x80000B00)
//flash status not ready within a timeout
#define ERROR_FLASH_NOT_READY (int)(0x80000C00)
//unable to retrieve fw_vers or the config_id
#define ERROR_FW_VER_READ (int)(0x80000D00)
//unable to enable/disable the gesture
#define ERROR_GESTURE_ENABLE_FAIL (int)(0x80000E00)
//unable to start to add custom gesture
#define ERROR_GESTURE_START_ADD (int)(0x80000F00)
//unable to finish to add custom gesture
#define ERROR_GESTURE_FINISH_ADD (int)(0x80001000)
//unable to add custom gesture data
#define ERROR_GESTURE_DATA_ADD (int)(0x80001100)
//unable to remove custom gesture data
#define ERROR_GESTURE_REMOVE (int)(0x80001200)
//unable to enable/disable a feature mode in the IC
#define ERROR_FEATURE_ENABLE_DISABLE (int)(0x80001300)
//unable to set/read noise parameter in the IC
#define ERROR_NOISE_PARAMETERS (int)(0x80001400)
//unable to write/rewrite/read lockdown code in the IC
#define ERROR_LOCKDOWN_CODE (int)(0x80001500)
//THIRD LEVEL ERROR CODE
//unable to retrieve the force and/or sense length
#define ERROR_CH_LEN (int)(0x80010000)
//compensation data request failed
#define ERROR_REQU_COMP_DATA (int)(0x80020000)
//unable to retrieve the compensation data header
#define ERROR_COMP_DATA_HEADER (int)(0x80030000)
//unable to retrieve the global compensation data
#define ERROR_COMP_DATA_GLOBAL (int)(0x80040000)
//unable to retrieve the compensation data for each node
#define ERROR_COMP_DATA_NODE (int)(0x80050000)
//check of production limits or of fw answers failed
#define ERROR_TEST_CHECK_FAIL (int)(0x80060000)
#define ERROR_MEMH_READ (int)(0x80070000)//memh reading failed
#define ERROR_FLASH_BURN_FAILED (int)(0x80080000)//flash burn failed
#define ERROR_MS_TUNING (int)(0x80090000)//ms tuning failed
#define ERROR_SS_TUNING (int)(0x800A0000)//ss tuning failed
//lp timer calibration failed
#define ERROR_LP_TIMER_TUNING (int)(0x800B0000)
//save cx data to flash failed
#define ERROR_SAVE_CX_TUNING (int)(0x800C0000)
//stop the poll of the FIFO if particular errors are found
#define ERROR_HANDLER_STOP_PROC (int)(0x800D0000)
//unable to retrieve echo event
#define ERROR_CHECK_ECHO_FAIL (int)(0x800E0000)
//FOURTH LEVEL ERROR CODE
//production data test failed
#define ERROR_PROD_TEST_DATA (int)(0x81000000)
//complete flash procedure failed
#define ERROR_FLASH_PROCEDURE (int)(0x82000000)
//production ito test failed
#define ERROR_PROD_TEST_ITO (int)(0x83000000)
//production initialization test failed
#define ERROR_PROD_TEST_INITIALIZATION (int)(0x84000000)
//mismatch of the MS or SS tuning_version
#define ERROR_GET_INIT_STATUS (int)(0x85000000)
void logError(int force, const char *msg, ...);
int isI2cError(int error);
int dumpErrorInfo(void);
int errorHandler(u8 *event, int size);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS API for Flashing the IC *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_FLASH_H
#define __FTS_FLASH_H
#include "ftsSoftware.h"
//Flash possible status
#define FLASH_READY 0
#define FLASH_BUSY 1
#define FLASH_UNKNOWN -1
#define FLASH_STATUS_BYTES 1
//Flash timing parameters
#define FLASH_RETRY_COUNT 1000
#define FLASH_WAIT_BEFORE_RETRY 50 //ms
#define FLASH_WAIT_TIME 200 //ms
//PATHS FW FILES
//#define PATH_FILE_FW "fw.memh"
#ifdef FTM3_CHIP
#define PATH_FILE_FW "st_fts.bin"
#else
#define PATH_FILE_FW "st_fts.ftb"//new bin file structure
#endif
#ifndef FTM3_CHIP
#define FLASH_CHUNK (64 * 1024)
#define DMA_CHUNK (2 * 1024)
#endif
struct Firmware {
u8 *data;
u16 fw_ver;
u16 config_id;
u8 externalRelease[EXTERNAL_RELEASE_INFO_SIZE];
int data_size;
#ifndef FTM3_CHIP
u32 sec0_size;
u32 sec1_size;
u32 sec2_size;
u32 sec3_size;
#endif
};
#ifdef FTM3_CHIP
int flash_status(void);
int flash_status_ready(void);
int wait_for_flash_ready(void);
#else
int wait_for_flash_ready(u8 type);
int fts_warm_boot(void);
int flash_erase_unlock(void);
int flash_full_erase(void);
int flash_erase_page_by_page(int keep_cx);
//int flash_erase_page_by_page_info(int page);
int start_flash_dma(void);
int fillFlash(u32 address, u8 *data, int size);
#endif
int flash_unlock(void);
int fillMemory(u32 address, u8 *data, int size);
int getFirmwareVersion(u16 *fw_vers, u16 *config_id);
int getFWdata(const char *pathToFile, u8 **data, int *size, int from);
int getFWdata_nocheck(const char *pathToFile, u8 **data, int *size, int from);
int parseBinFile(u8 *fw_data, int fw_size, struct Firmware *fw, int keep_cx);
int readFwFile(const char *path, struct Firmware *fw, int keep_cx);
int flash_burn(struct Firmware *fw, int force_burn, int keep_cx);
int flashProcedure(const char *path, int force, int keep_cx);
#endif

View file

@ -0,0 +1,519 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting frames *
* *
**************************************************************************
**************************************************************************
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
//#include <linux/sec_sysfs.h>
#include "ftsCrossCompile.h"
#include "ftsCompensation.h"
#include "ftsError.h"
#include "ftsFrame.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsSoftware.h"
#include "ftsTool.h"
#include "ftsTime.h"
#include "../fts.h"
static char tag[8] = "[ FTS ]\0";
static int sense_len, force_len;
int getOffsetFrame(u16 address, u16 *offset)
{
u8 data[2];
u8 cmd = { FTS_CMD_FRAMEBUFFER_R };
char *temp = NULL;
if (readCmdU16(cmd, address, data, OFFSET_LENGTH,
DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %S: ERROR %02X\n", tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
u8ToU16(data, offset);
temp = printHex("Offest = ", data, OFFSET_LENGTH);
if (temp != NULL)
logError(0, "%s %s", tag, temp);
kfree(temp);
return OK;
}
int getChannelsLength(void)
{
int ret;
u8 *data = (u8 *)kmalloc_array(2, sizeof(u8), GFP_KERNEL);
if (data == NULL) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = readB2(ADDR_SENSE_LEN, data, 2);
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_READ_B2);
kfree(data);
return (ret|ERROR_READ_B2);
}
sense_len = (int)data[0];
force_len = (int)data[1];
logError(0, "%s Force_len = %d Sense_Len = %d\n",
tag, force_len, sense_len);
kfree(data);
return OK;
}
int getFrameData(u16 address, int size, short **frame)
{
int i, j, ret;
u8 *data = (u8 *)kmalloc_array(size, sizeof(u8), GFP_KERNEL);
if (data == NULL) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = readCmdU16(FTS_CMD_FRAMEBUFFER_R, address,
data, size, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
kfree(data);
return ERROR_I2C_R;
}
j = 0;
for (i = 0; i < size; i += 2) {
(*frame)[j] = (short)((data[i + 1] << 8) + data[i]);
j++;
}
kfree(data);
return OK;
}
int getMSFrame(u16 type, struct MutualSenseFrame *frame, int keep_first_row)
{
u16 offset;
int ret;
if (getSenseLen() == 0 || getForceLen() == 0) {
ret = getChannelsLength();
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_CH_LEN);
return (ret|ERROR_CH_LEN);
}
}
ret = getOffsetFrame(type, &offset);
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_GET_OFFSET);
return (ret | ERROR_GET_OFFSET);
}
switch (type) {
case ADDR_RAW_TOUCH:
case ADDR_FILTER_TOUCH:
case ADDR_NORM_TOUCH:
case ADDR_CALIB_TOUCH:
if (keep_first_row == 1) {
frame->node_data_size = ((force_len + 1) * sense_len);
frame->header.force_node = force_len + 1;
} else {
frame->node_data_size = ((force_len) * sense_len);
offset += (sense_len * BYTES_PER_NODE);
frame->header.force_node = force_len;
}
frame->header.sense_node = sense_len;
break;
case ADDR_NORM_MS_KEY:
case ADDR_RAW_MS_KEY:
frame->header.force_node = 1;
frame->header.sense_node = ftsInfo.u8_msKeyLen;
frame->node_data_size = ftsInfo.u8_msKeyLen;
break;
default:
logError(1, "%s %s: ERROR % 02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
frame->node_data = (short *)kmalloc_array(frame->node_data_size,
sizeof(short), GFP_KERNEL);
if (frame->node_data == NULL) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = getFrameData(offset,
frame->node_data_size * BYTES_PER_NODE,
&(frame->node_data));
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_GET_FRAME_DATA);
kfree(frame->node_data);
return (ret | ERROR_GET_FRAME_DATA);
}
// if you want to access one node i,j,
//you should compute the offset like:
//offset = i * columns + j => frame[i, j]
logError(0, "%s Frame acquired!\n", tag);
//return the number of data put inside frame
return frame->node_data_size;
}
int getSenseLen(void)
{
int ret;
if (sense_len != 0)
return sense_len;
if (ftsInfo.u8_scrSenseLen != 0) {
sense_len = ftsInfo.u8_scrSenseLen;
} else {
ret = getChannelsLength();
if (ret < OK)
return ret;
}
return sense_len;
}
int getForceLen(void)
{
int ret;
if (force_len != 0)
return force_len;
if (ftsInfo.u8_scrForceLen != 0) {
force_len = ftsInfo.u8_scrForceLen;
} else {
ret = getChannelsLength();
if (ret < OK)
return ret;
}
return force_len;
}
int requestFrame(u16 type)
{
int retry = 0;
int ret;
u16 answer;
char *temp = NULL;
int event_to_search[1];
u8 readEvent[FIFO_EVENT_SIZE];
u8 cmd[3] = { FTS_CMD_REQU_FRAME_DATA, 0x00, 0x00};
// B7 is the command for asking frame data
event_to_search[0] = (int)EVENTID_FRAME_DATA_READ;
u16ToU8(type, &cmd[1]);
while (retry < FRAME_DATA_READ_RETRY) {
temp = printHex("Command = ", cmd, 3);
if (temp != NULL)
logError(0, "%s %s", tag, temp);
kfree(temp);
//send the request to the chip to load in memory the Frame Data
ret = fts_writeFwCmd(cmd, 3);
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
}
ret = pollForEvent(event_to_search,
1,
readEvent,
TIMEOUT_REQU_COMP_DATA);
if (ret < OK) {
logError(0, "%s Event did not Found at %d attemp!\n",
tag, retry + 1);
retry += 1;
} else {
retry = 0;
break;
}
}
if (retry == FRAME_DATA_READ_RETRY) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_TIMEOUT);
return ERROR_TIMEOUT;
}
u8ToU16_le(&readEvent[1], &answer);
if (answer == type)
return OK;
logError(1, "%s The event found has a different type of ", tag);
logError(1, "Frame data:%02X\n", ERROR_DIFF_COMP_TYPE);
return ERROR_DIFF_COMP_TYPE;
}
int readFrameDataHeader(u16 type, struct DataHeader *header)
{
u16 offset = ADDR_FRAMEBUFFER_DATA;
u16 answer;
u8 data[FRAME_DATA_HEADER];
if (readCmdU16(FTS_CMD_FRAMEBUFFER_R, offset, data,
FRAME_DATA_HEADER, DUMMY_FRAMEBUFFER) < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
logError(0, "%s Read Data Header done!\n", tag);
if (data[0] != FRAME_HEADER_SIGNATURE) {
logError(1, "%s %s %02X Wrong Header Signature !%02X != %02X\n",
tag, __func__, ERROR_WRONG_COMP_SIGN, data[0],
HEADER_SIGNATURE);
return ERROR_WRONG_COMP_SIGN;
}
u8ToU16_le(&data[1], &answer);
if (answer != type) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_DIFF_COMP_TYPE);
return ERROR_DIFF_COMP_TYPE;
}
logError(0, "%s Type of Frame data OK!\n", tag);
header->type = type;
header->force_node = (int)data[4];
header->sense_node = (int)data[5];
return OK;
}
int getMSFrame2(u16 type, struct MutualSenseFrame *frame)
{
u16 offset = ADDR_FRAMEBUFFER_DATA+FRAME_DATA_HEADER;
int size, ret;
frame->node_data = NULL;
if (!(type == MS_TOUCH_ACTIVE || type == MS_TOUCH_LOW_POWER
|| type == MS_TOUCH_ULTRA_LOW_POWER
|| type == MS_KEY)) {
logError(1, "%s %s:Choose a MS type of frame data ERROR %02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestFrame(type);
if (ret < 0) {
logError(1, "%s readMutualSenseCompensation:ERROR %02X\n",
tag, ERROR_REQU_COMP_DATA);
return (ret | ERROR_REQU_COMP_DATA);
}
ret = readFrameDataHeader(type, &(frame->header));
if (ret < 0) {
logError(1, "%s readMutualSenseCompensationData:ERROR %02X\n",
tag, ERROR_COMP_DATA_HEADER);
return (ret | ERROR_COMP_DATA_HEADER);
}
switch (type) {
case MS_TOUCH_ACTIVE:
case MS_TOUCH_LOW_POWER:
case MS_TOUCH_ULTRA_LOW_POWER:
size = frame->header.force_node * frame->header.sense_node;
break;
case MS_KEY:
//or use directly the number in the ftsChip
if (frame->header.force_node > frame->header.sense_node)
size = frame->header.force_node;
else
size = frame->header.sense_node;
frame->header.force_node = 1;
frame->header.sense_node = size;
break;
default:
logError(1, "%s %s: ERROR % 02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
frame->node_data = (short *)kmalloc_array(size,
sizeof(short), GFP_KERNEL);
if (frame->node_data == NULL) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = getFrameData(offset, size*BYTES_PER_NODE, &(frame->node_data));
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_GET_FRAME_DATA);
kfree(frame->node_data);
return (ret | ERROR_GET_FRAME_DATA);
}
// if you want to access one node i,j,
//you should compute the offset like:
//offset = i * columns + j = > frame[i, j]
logError(0, "%s Frame acquired!\n", tag);
frame->node_data_size = size;
return size;//return the number of data put inside frame
}
int getSSFrame2(u16 type, struct SelfSenseFrame *frame)
{
u16 offset = ADDR_FRAMEBUFFER_DATA + FRAME_DATA_HEADER;
int size, ret;
short *temp = NULL;
frame->force_data = NULL;
frame->sense_data = NULL;
if (!(type == SS_TOUCH || type == SS_KEY || type == SS_HOVER
|| type == SS_PROXIMITY)) {
logError(1, "%s %s:Choose a SS type of frame data ERROR %02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestFrame(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_REQU_COMP_DATA);
return (ret | ERROR_REQU_COMP_DATA);
}
ret = readFrameDataHeader(type, &(frame->header));
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_COMP_DATA_HEADER);
return (ret | ERROR_COMP_DATA_HEADER);
}
switch (type) {
case SS_TOUCH:
case SS_HOVER:
case SS_PROXIMITY:
size = frame->header.force_node + frame->header.sense_node;
break;
default:
logError(1, "%s %s: ERROR % 02X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
temp = (short *)kmalloc_array(size, sizeof(short), GFP_KERNEL);
if (temp == NULL) {
logError(1, "%s %s: temp ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = getFrameData(offset, size*BYTES_PER_NODE, &temp);
if (ret < OK) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_GET_FRAME_DATA);
kfree(temp);
return (ret | ERROR_GET_FRAME_DATA);
}
frame->force_data = (short *)kmalloc_array(frame->header.force_node,
sizeof(short), GFP_KERNEL);
if (frame->force_data == NULL) {
logError(1, "%s %s: frame->force_data ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
kfree(temp);
return ERROR_ALLOC;
}
memcpy(frame->force_data, temp,
frame->header.force_node * sizeof(short));
frame->sense_data = (short *)kmalloc_array(frame->header.sense_node,
sizeof(short), GFP_KERNEL);
if (frame->sense_data == NULL) {
logError(1, "%s %s: frame->sense_data ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
kfree(temp);
kfree(frame->force_data);
return ERROR_ALLOC;
}
memcpy(frame->sense_data, &temp[frame->header.force_node],
frame->header.sense_node * sizeof(short));
logError(0, "%s Frame acquired!\n", tag);
kfree(temp);
return size; //return the number of data put inside frame
}

View file

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting frames *
* *
**************************************************************************
**************************************************************************
*/
#ifndef __FTS_FRAME_H
#define __FTS_FRAME_H
#include "ftsSoftware.h"
//Number of data bytes for each node
#define BYTES_PER_NODE 2
#define OFFSET_LENGTH 2
#define FRAME_DATA_HEADER 8
#define FRAME_HEADER_SIGNATURE 0xB5
#define FRAME_DATA_READ_RETRY 2
struct MutualSenseFrame {
struct DataHeader header;
short *node_data;
int node_data_size;
};
struct SelfSenseFrame {
struct DataHeader header;
short *force_data;
short *sense_data;
};
int getOffsetFrame(u16 address, u16 *offset);
int getChannelsLength(void);
int getFrameData(u16 address, int size, short **frame);
int getMSFrame(u16 type, struct MutualSenseFrame *frame, int keep_first_row);
//int getMSKeyFrame(u16 type, short **frame);
//int getSSFrame(u16 type, short **frame);
//int getNmsFrame(u16 type, short ***frames, int * sizes,
//int keep_first_row, int fs, int n);
int getSenseLen(void);
int getForceLen(void);
int requestFrame(u16 type);
int readFrameDataHeader(u16 type, struct DataHeader *header);
int getMSFrame2(u16 type, struct MutualSenseFrame *frame);
int getSSFrame2(u16 type, struct SelfSenseFrame *frame);
#endif

View file

@ -0,0 +1,651 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Gesture Utilities *
* *
**************************************************************************
**************************************************************************
*/
#include "ftsSoftware.h"
#include "ftsError.h"
#include "ftsGesture.h"
#include "ftsIO.h"
#include "ftsTool.h"
static char tag[8] = "[ FTS ]\0";
static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 };
static u8 custom_gestures[GESTURE_CUSTOM_NUMBER][GESTURE_CUSTOM_POINTS];
static u8 custom_gesture_index[GESTURE_CUSTOM_NUMBER] = { 0 };
static int refreshGestureMask;
u16 gesture_coordinates_x[GESTURE_COORDS_REPORT_MAX] = {0};
u16 gesture_coordinates_y[GESTURE_COORDS_REPORT_MAX] = {0};
int gesture_coords_reported = ERROR_OP_NOT_ALLOW;
struct mutex gestureMask_mutex;
int updateGestureMask(u8 *mask, int size, int en)
{
u8 temp;
int i;
if (mask == NULL) {
logError(1, "%s %s: Mask NULL! ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
if (size > GESTURE_MASK_SIZE) {
logError(1, "%s %s:Size not valid! %d > %d ERROR %08X\n",
tag, __func__, size, GESTURE_MASK_SIZE);
return ERROR_OP_NOT_ALLOW;
}
if (en == FEAT_ENABLE) {
mutex_lock(&gestureMask_mutex);
logError(0, "%s %s:setting gesture mask to enable..\n",
tag, __func__);
if (mask != NULL) {
for (i = 0; i < size; i++) {
//back up the gesture enabled
gesture_mask[i] = gesture_mask[i] | mask[i];
}
}
refreshGestureMask = 1;
logError(0, "%s %s:gesture mask to enable SET!\n",
tag, __func__);
mutex_unlock(&gestureMask_mutex);
return OK;
}
if (en == FEAT_DISABLE) {
mutex_lock(&gestureMask_mutex);
logError(0, "%s %s:setting gesture ", tag, __func__);
logError(0, "mask to disable...\n");
for (i = 0; i < size; i++) {
// enabled XOR disabled
temp = gesture_mask[i] ^ mask[i];
gesture_mask[i] = temp & gesture_mask[i];
}
logError(0, "%s %s:gesture mask to disable SET!\n",
tag, __func__);
refreshGestureMask = 1;
mutex_unlock(&gestureMask_mutex);
return OK;
}
logError(1, "%s%s:Enable parameter Invalid%d!=%d or%d%:08X",
tag, __func__, FEAT_DISABLE,
FEAT_ENABLE, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
int enableGesture(u8 *mask, int size)
{
u8 cmd[GESTURE_MASK_SIZE + 2];
u8 readData[FIFO_EVENT_SIZE] = {0};
int i, res;
int event_to_search[4] = { EVENTID_GESTURE,
EVENT_TYPE_ENB, 0x00, GESTURE_ENABLE };
logError(0, "%s Trying to enable gesture...\n", tag);
cmd[0] = FTS_CMD_GESTURE_CMD;
cmd[1] = GESTURE_ENABLE;
if (size > GESTURE_MASK_SIZE) {
logError(1, "%s %s: Size not valid! %d > %d ERROR %08X\n",
tag, __func__, size, GESTURE_MASK_SIZE);
return ERROR_OP_NOT_ALLOW;
}
mutex_lock(&gestureMask_mutex);
if (mask != NULL) {
for (i = 0; i < size; i++) {
cmd[i + 2] = mask[i];
//back up of the gesture enabled
gesture_mask[i] = gesture_mask[i] | mask[i];
}
while (i < GESTURE_MASK_SIZE) {
cmd[i + 2] = gesture_mask[i];
i++;
}
} else {
for (i = 0; i < GESTURE_MASK_SIZE; i++)
cmd[i + 2] = gesture_mask[i];
}
res = fts_writeFwCmd(cmd, GESTURE_MASK_SIZE + 2);
if (res < OK) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__, res);
goto END;
}
res = pollForEvent(event_to_search, 4,
readData, GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s: pollForEvent ERROR %08X\n",
tag, __func__, res);
goto END;
}
if (readData[4] != 0x00) {
logError(1, "%s %s: ERROR %08X\n",
tag, __func__, ERROR_GESTURE_ENABLE_FAIL);
res = ERROR_GESTURE_ENABLE_FAIL;
goto END;
}
logError(0, "%s %s: DONE!\n", tag, __func__);
res = OK;
END:
mutex_unlock(&gestureMask_mutex);
return res;
}
int disableGesture(u8 *mask, int size)
{
u8 cmd[2 + GESTURE_MASK_SIZE];
u8 readData[FIFO_EVENT_SIZE] = {0};
u8 temp;
int i, res;
int event_to_search[4] = { EVENTID_GESTURE,
EVENT_TYPE_ENB, 0x00, GESTURE_DISABLE };
logError(0, "%s Trying to disable gesture...\n", tag);
cmd[0] = FTS_CMD_GESTURE_CMD;
cmd[1] = GESTURE_DISABLE;
if (size > GESTURE_MASK_SIZE) {
logError(1, "%s %s: Size not valid! %d > %d ERROR %08X\n",
tag, __func__, size, GESTURE_MASK_SIZE);
return ERROR_OP_NOT_ALLOW;
}
mutex_lock(&gestureMask_mutex);
if (mask != NULL) {
for (i = 0; i < size; i++) {
cmd[i + 2] = mask[i];
// enabled XOR disabled
temp = gesture_mask[i] ^ mask[i];
gesture_mask[i] = temp & gesture_mask[i];
}
while (i < GESTURE_MASK_SIZE) {
//cmd[i + 2] = gesture_mask[i];
//gesture_mask[i] = 0x00;
cmd[i + 2] = 0x00;
//leave untouched the gestures not specified
i++;
}
} else {
for (i = 0; i < GESTURE_MASK_SIZE; i++) {
//cmd[i + 2] = gesture_mask[i];
cmd[i + 2] = 0xFF;
}
}
res = fts_writeFwCmd(cmd, 2 + GESTURE_MASK_SIZE);
if (res < OK) {
logError(1, "%s %s:ERROR %08X\n", tag, __func__, res);
goto END;
}
res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s: pollForEvent ERROR %08X\n",
tag, __func__, res);
goto END;
}
if (readData[4] != 0x00) {
logError(1, "%s %s:ERROR %08X\n",
tag, __func__, ERROR_GESTURE_ENABLE_FAIL);
res = ERROR_GESTURE_ENABLE_FAIL;
goto END;
}
logError(0, "%s %s: DONE!\n", tag, __func__);
res = OK;
END:
mutex_unlock(&gestureMask_mutex);
return res;
}
int startAddCustomGesture(u8 gestureID)
{
u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GESTURE_START_ADD, gestureID };
int res;
u8 readData[FIFO_EVENT_SIZE] = {0};
int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB,
gestureID, GESTURE_START_ADD };
res = fts_writeFwCmd(cmd, 3);
if (res < OK) {
logError(1,
"%s%s:Impossible to start adding custom gesture ID:%02X %08X\n",
tag, __func__, gestureID, res);
return res;
}
res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s:start add event not found! ERROR %08X\n",
tag, __func__, res);
return res;
}
//check of gestureID is redundant
if (readData[2] != gestureID || readData[4] != 0x00) {
logError(1, "%s %s:start add event status not OK! ERROR %08X\n",
tag, __func__, readData[4]);
return ERROR_GESTURE_START_ADD;
}
return OK;
}
int finishAddCustomGesture(u8 gestureID)
{
u8 cmd[3] = { FTS_CMD_GESTURE_CMD,
GESTURE_FINISH_ADD, gestureID };
int res;
u8 readData[FIFO_EVENT_SIZE] = {0};
int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB,
gestureID, GESTURE_FINISH_ADD };
res = fts_writeFwCmd(cmd, 3);
if (res < OK) {
logError(1,
"%s%s:Impossible to finish adding custom gestureID:%02X %08X\n",
tag, __func__, gestureID, res);
return res;
}
res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s: finish add event not found! ERROR %08X\n",
tag, __func__, res);
return res;
}
//check of gestureID is redundant
if (readData[2] != gestureID || readData[4] != 0x00) {
logError(1,
"%s %s:finish add event status not OK! ERROR %08X\n",
tag, __func__, readData[4]);
return ERROR_GESTURE_FINISH_ADD;
}
return OK;
}
int loadCustomGesture(u8 *template, u8 gestureID)
{
int res, i, wheel;
int remaining = GESTURE_CUSTOM_POINTS;
int toWrite, offset = 0;
u8 cmd[TEMPLATE_CHUNK + 5];
int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB,
gestureID, GESTURE_DATA_ADD };
u8 readData[FIFO_EVENT_SIZE] = {0};
logError(0, "%s Starting adding custom gesture procedure...\n", tag);
res = startAddCustomGesture(gestureID);
if (res < OK) {
logError(1, "%s %s:unable to start adding procedure %08X\n",
tag, __func__, res);
return res;
}
cmd[0] = FTS_CMD_GESTURE_CMD;
cmd[1] = GESTURE_DATA_ADD;
cmd[2] = gestureID;
wheel = 0;
while (remaining > 0) {
if (remaining > TEMPLATE_CHUNK)
toWrite = TEMPLATE_CHUNK;
else
toWrite = remaining;
cmd[3] = toWrite;
cmd[4] = offset;
for (i = 0; i < toWrite; i++)
cmd[i + 5] = template[wheel++];
res = fts_writeFwCmd(cmd, toWrite + 5);
if (res < OK) {
logError(1, "%s %s:unable to start ", tag, __func__);
logError(1, "adding procedure %08X\n", res);
return res;
}
res = pollForEvent(event_to_search,
4,
readData,
GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s: add event not found! ERROR %08X\n",
tag, __func__, res);
return res;
}
//check of gestureID is redundant
if (readData[2] != gestureID || readData[4] != 0x00) {
logError(1, "%s %s:add event status not OK! ",
tag, __func__);
logError(1, "ERROR %08X\n", readData[4]);
return ERROR_GESTURE_DATA_ADD;
}
remaining -= toWrite;
offset += toWrite / 2;
}
res = finishAddCustomGesture(gestureID);
if (res < OK) {
logError(1, "%s %s:unable to finish adding procedure! ",
tag, __func__);
logError(1, "ERROR %08X\n", res);
return res;
}
logError(0, "%s Adding custom gesture procedure DONE!\n", tag);
return OK;
}
int reloadCustomGesture(void)
{
int res, i;
logError(0, "%s Starting reload Gesture Template...\n", tag);
for (i = 0; i < GESTURE_CUSTOM_NUMBER; i++) {
if (custom_gesture_index[i] == 1) {
res = loadCustomGesture(custom_gestures[i],
GESTURE_CUSTOM_OFFSET + i);
if (res < OK) {
logError(1, "%s %s:Impossible load gesture ",
tag, __func__);
logError(1, "D:%02X %08X\n",
GESTURE_CUSTOM_OFFSET + i, res);
return res;
}
}
}
logError(0, "%s Reload Gesture Template DONE!\n", tag);
return OK;
}
int enterGestureMode(int reload)
{
u8 cmd = FTS_CMD_GESTURE_MODE;
int res, ret;
res = fts_disableInterrupt();
if (res < OK) {
logError(1, "%s %s: ERROR %08X\n",
tag, __func__, res | ERROR_DISABLE_INTER);
return res | ERROR_DISABLE_INTER;
}
if (reload == 1 || refreshGestureMask == 1) {
if (reload == 1) {
res = reloadCustomGesture();
if (res < OK) {
logError(1, "%s %s:impossible reload ",
tag, __func__);
logError(1, "custom gesture %08X\n", res);
goto END;
}
}
/**
* mandatory steps to set the correct gesture
* mask defined by the user
*/
res = disableGesture(NULL, 0);
if (res < OK) {
logError(1, "%s %s:disableGesture ERROR %08X\n",
tag, res);
goto END;
}
res = enableGesture(NULL, 0);
if (res < OK) {
logError(1, "%s %s:enableGesture ERROR %08X\n",
tag, __func__, res);
goto END;
}
refreshGestureMask = 0;
/**************************************************/
}
res = fts_writeFwCmd(&cmd, 1);
if (res < OK) {
logError(1, "%s %s:enter gesture mode ERROR %08X\n",
tag, __func__, res);
goto END;
}
res = OK;
END:
ret = fts_enableInterrupt();
if (ret < OK) {
logError(1, "%s %s:fts_enableInterrupt ERROR %08X\n",
tag, __func__, res | ERROR_ENABLE_INTER);
res |= ret | ERROR_ENABLE_INTER;
}
return res;
}
int addCustomGesture(u8 *data, int size, u8 gestureID)
{
int index, res, i;
index = gestureID - GESTURE_CUSTOM_OFFSET;
logError(0, "%s Starting Custom Gesture Adding procedure...\n", tag);
if (size != GESTURE_CUSTOM_POINTS || (gestureID != GES_ID_CUST1
&& gestureID != GES_ID_CUST2 && gestureID != GES_ID_CUST3
&& gestureID != GES_ID_CUST4 && gestureID != GES_ID_CUST5)) {
logError(1, "%s %s:Invalid size(%d) or Custom GestureID ",
tag, __func__, size);
logError(1, "(%02X)!ERROR%08X\n",
size, gestureID, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
for (i = 0; i < GESTURE_CUSTOM_POINTS; i++)
custom_gestures[index][i] = data[i];
res = loadCustomGesture(custom_gestures[index], gestureID);
if (res < OK) {
logError(1, "%s %s:impossible to load the custom gesture! ",
tag, __func__);
logError(1, "ERROR %08X\n", res);
return res;
}
custom_gesture_index[index] = 1;
logError(0, "%s Custom Gesture Adding procedure DONE!\n", tag);
return OK;
}
int removeCustomGesture(u8 gestureID)
{
int res, index;
u8 cmd[3] = { FTS_CMD_GESTURE_CMD, GETURE_REMOVE_CUSTOM, gestureID };
int event_to_search[4] = { EVENTID_GESTURE, EVENT_TYPE_ENB,
gestureID, GETURE_REMOVE_CUSTOM };
u8 readData[FIFO_EVENT_SIZE] = {0};
index = gestureID - GESTURE_CUSTOM_OFFSET;
logError(0, "%s Starting Custom Gesture Removing procedure...\n", tag);
if (gestureID != GES_ID_CUST1 && gestureID != GES_ID_CUST2 &&
gestureID != GES_ID_CUST3 && gestureID !=
GES_ID_CUST4 && gestureID != GES_ID_CUST5) {
logError(1, "%s %s:Invalid Custom GestureID (%02X)! ",
tag, __func__, gestureID);
logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
//when a gesture is removed, it is also disabled automatically
res = fts_writeFwCmd(cmd, 3);
if (res < OK) {
logError(1, "%s %s:Impossible to remove custom ",
tag, __func__);
logError(1, "%gesture ID:%02X %08X\n", gestureID, res);
return res;
}
res = pollForEvent(event_to_search, 4, readData, GENERAL_TIMEOUT);
if (res < OK) {
logError(1, "%s %s:remove event not found! ERROR %08X\n",
tag, __func__, res);
return res;
}
//check of gestureID is redundant
if (readData[2] != gestureID || readData[4] != 0x00) {
logError(1, "%s %s:remove event status not OK! ERROR %08X\n",
tag, __func__, readData[4]);
return ERROR_GESTURE_REMOVE;
}
custom_gesture_index[index] = 0;
logError(0, "%s Custom Gesture Remove procedure DONE!\n", tag);
return OK;
}
int isAnyGestureActive(void)
{
int res = 0;
/*-1 because in any case the last gesture mask byte will*/
/*be evaluated with the following if*/
while (res < (GESTURE_MASK_SIZE - 1) && gesture_mask[res] == 0)
res++;
if (gesture_mask[res] == 0) {
logError(0, "%s %s: All Gestures Disabled!\n", tag, __func__);
return FEAT_DISABLE;
}
logError(0, "%s %s:Active Gestures Found! gesture_mask[%d] = %02X!\n",
tag, __func__, res, gesture_mask[res]);
return FEAT_ENABLE;
}
int gestureIDtoGestureMask(u8 id, u8 *mask)
{
logError(0, "%s %s: Index = %d Position = %d!\n",
tag, __func__, ((int)((id) / 8)), (id % 8));
mask[((int)((id) / 8))] |= 0x01 << (id % 8);
return OK;
}
int readGestureCoords(u8 *event)
{
int i = 0;
u8 rCmd[3] = {FTS_CMD_FRAMEBUFFER_R, 0x00, 0x00 };
int res;
unsigned char val[GESTURE_COORDS_REPORT_MAX * 4 + 1];
//the max coordinates to read are GESTURE_COORDS_REPORT_MAX*4
//(because each coordinate is a short(*2) and we have x and y)
//+ dummy byte
if (event[0] != EVENTID_GESTURE
|| event[1] != EVENT_TYPE_GESTURE_DTC2) {
logError(1, "%s %s:The event passsed as argument is invalid! ",
tag, __func__);
logError(1, "ERROR %08X\n", ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
rCmd[1] = event[4]; // Offset address L
rCmd[2] = event[3]; // Offset address H
//number of coords reported L
gesture_coords_reported = event[6];
//number of coords reported H
gesture_coords_reported = (gesture_coords_reported << 8) | event[5];
if (gesture_coords_reported > GESTURE_COORDS_REPORT_MAX) {
logError(1, "%s%s:FW reported more than:%d points ",
tag, __func__, gesture_coords_reported);
logError(1, "for gestures!\n");
logError(1, " Decreasing to %d\n", GESTURE_COORDS_REPORT_MAX);
gesture_coords_reported = GESTURE_COORDS_REPORT_MAX;
}
logError(1, "%s %s: Offset: %02X %02X points = %d\n", tag,
__func__, rCmd[1], rCmd[2], gesture_coords_reported);
res = fts_readCmd(rCmd, 3, (unsigned char *)val,
1 + (gesture_coords_reported * 2));
if (res < OK) {
logError(1, "%s %s: Cannot read the coordinates! ERROR %08X\n",
tag, __func__, res);
gesture_coords_reported = ERROR_OP_NOT_ALLOW;
return res;
}
//all the points of the gesture are stored in val
for (i = 0; i < gesture_coords_reported; i++) {
//ignore first byte data because it is a dummy byte
gesture_coordinates_x[i] = (((u16) val[i * 2 + 1 + 1])
& 0x0F) << 8 | (((u16) val[i * 2 + 1]) & 0xFF);
gesture_coordinates_y[i] =
(((u16)val[gesture_coords_reported * 2
+ i * 2 + 1 + 1]) & 0x0F) << 8
| (((u16)val[gesture_coords_reported * 2
+ i * 2 + 1]) & 0xFF);
}
logError(1, "%s %s: Reading Gesture Coordinates DONE!\n",
tag, __func__);
return OK;
}
int getGestureCoords(u16 *x, u16 *y)
{
x = gesture_coordinates_x;
y = gesture_coordinates_y;
logError(1, "%s %s:Number of gesture coordinates returned = %d\n",
tag, __func__, gesture_coords_reported);
return gesture_coords_reported;
}

View file

@ -0,0 +1,123 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Gesture Utilities *
* *
**************************************************************************
**************************************************************************
*/
#ifndef _FTS_GESTURE_H_
#define _FTS_GESTURE_H_
#include "ftsHardware.h"
#define GESTURE_MASK_SIZE 8
//max number of gestures coordinates reported
#define GESTURE_COORDS_REPORT_MAX 32
// for each custom gesture should be provided 30
//points (each point is a couple of x,y)
#define GESTURE_CUSTOM_POINTS (30 * 2)
//fw support up to 5 custom gestures
#define GESTURE_CUSTOM_NUMBER 5
#ifdef FTM3
//number of points to transfer with each I2C transaction
#define TEMPLATE_CHUNK (10 * 2)
#else
//number of points to transfer with each I2C transaction
#define TEMPLATE_CHUNK (5 * 2)
#endif
//Gesture IDs
#define GES_ID_UNKNOWN 0x00 //no meaningful gesture
#define GES_ID_DBLTAP 0x01 //Double Tap
#define GES_ID_O 0x02 //'O'
#define GES_ID_C 0x03 //'C'
#define GES_ID_M 0x04 //'M'
#define GES_ID_W 0x05 //'W'
#define GES_ID_E 0x06 //'e'
#define GES_ID_HFLIP_L2R 0x07 //Left to right line
#define GES_ID_HFLIP_R2L 0x08 //Right to left line
#define GES_ID_VFLIP_T2D 0x09 //Top to bottom line
#define GES_ID_VFLIP_D2T 0x0A //Bottom to Top line
#define GES_ID_L 0x0B //'L'
#define GES_ID_F 0x0C //'F'
#define GES_ID_V 0x0D //'V'
#define GES_ID_AT 0x0E //'@'
#define GES_ID_S 0x0F //'S'
#define GES_ID_Z 0x10 //'Z'
#define GES_ID_CUST1 0x11 //Custom gesture 1
#define GES_ID_CUST2 0x12 //Custom gesture 2
#define GES_ID_CUST3 0x13 //Custom gesture 3
#define GES_ID_CUST4 0x14 //Custom gesture 4
#define GES_ID_CUST5 0x15 //Custom gesture 5
#define GES_ID_LEFTBRACE 0x20 //'<'
#define GES_ID_RIGHTBRACE 0x21 //'>'
#define GESTURE_CUSTOM_OFFSET GES_ID_CUST1
//Command sub-type
#define GESTURE_ENABLE 0x01
#define GESTURE_DISABLE 0x02
#define GESTURE_ENB_CHECK 0x03
#define GESTURE_START_ADD 0x10
#define GESTURE_DATA_ADD 0x11
#define GESTURE_FINISH_ADD 0x12
#define GETURE_REMOVE_CUSTOM 0x13
#define GESTURE_CHECK_CUSTOM 0x14
//Event sub-type
#define EVENT_TYPE_ENB 0x04
#define EVENT_TYPE_CHECK_ENB 0x03
#define EVENT_TYPE_GESTURE_DTC1 0x01
#define EVENT_TYPE_GESTURE_DTC2 0x02
int updateGestureMask(u8 *mask, int size, int en);
int disableGesture(u8 *mask, int size);
int enableGesture(u8 *mask, int size);
int startAddCustomGesture(u8 gestureID);
int finishAddCustomGesture(u8 gestureID);
int loadCustomGesture(u8 *template, u8 gestureID);
int reloadCustomGesture(void);
int enterGestureMode(int reload);
int addCustomGesture(u8 *data, int size, u8 gestureID);
int removeCustomGesture(u8 gestureID);
int isAnyGestureActive(void);
int gestureIDtoGestureMask(u8 id, u8 *mask);
int readGestureCoords(u8 *event);
int getGestureCoords(u16 *x, u16 *y);
#endif

View file

@ -0,0 +1,213 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* HW related data **
* *
**************************************************************************
**************************************************************************
*/
#ifndef __FTS_HARDWARE_H
#define __FTS_HARDWARE_H
//DUMMY BYTES DATA
#define DUMMY_HW_REG 1
#define DUMMY_FRAMEBUFFER 1
#define DUMMY_MEMORY 1
//DIGITAL CHIP INFO
#ifdef FTM3_CHIP
#define DCHIP_ID_0 0x39
#define DCHIP_ID_1 0x6C
#else
#define DCHIP_ID_0 0x36
#define DCHIP_ID_1 0x70
#endif
#ifdef FTM3_CHIP
#define DCHIP_ID_ADDR 0x0007
#define DCHIP_FW_VER_ADDR 0x000A
#else
#define DCHIP_ID_ADDR 0x0004
#define DCHIP_FW_VER_ADDR 0x0008
#endif
#define DCHIP_FW_VER_BYTE 2
//CHUNKS
#define READ_CHUNK (2 * 1024)
#define WRITE_CHUNK (2 * 1024)
#define MEMORY_CHUNK (2 * 1024)
//PROTOCOL INFO
#ifdef FTM3_CHIP
#define I2C_SAD 0x49
#else
#define I2C_SAD 0x49
#endif
#define I2C_INTERFACE //comment if the chip use SPI
#define ICR_ADDR 0x0024
#define ICR_SPI_VALUE 0x02
//SYSTEM RESET INFO
#ifdef FTM3_CHIP
#define SYSTEM_RESET_ADDRESS 0x0023
#define SYSTEM_RESET_VALUE 0x01
#else
#define SYSTEM_RESET_ADDRESS 0x0028
#define SYSTEM_RESET_VALUE 0x80
#endif
//INTERRUPT INFO
#ifdef FTM3_CHIP
#define IER_ADDR 0x001C
#else
#define IER_ADDR 0x002C
#endif
#define IER_ENABLE 0x41
#define IER_DISABLE 0x00
//FLASH COMMAND
#define FLASH_CMD_UNLOCK 0xF7
#ifdef FTM3_CHIP
#define FLASH_CMD_WRITE_LOWER_64 0xF0
#define FLASH_CMD_WRITE_UPPER_64 0xF1
#define FLASH_CMD_BURN 0xF2
#define FLASH_CMD_ERASE 0xF3
#define FLASH_CMD_READSTATUS 0xF4
#else
#define FLASH_CMD_WRITE_64K 0xF8
#define FLASH_CMD_READ_REGISTER 0xF9
#define FLASH_CMD_WRITE_REGISTER 0xFA
#endif
//FLASH UNLOCK PARAMETER
#define FLASH_UNLOCK_CODE0 0x74
#define FLASH_UNLOCK_CODE1 0x45
#ifndef FTM3_CHIP
//FLASH ERASE and DMA PARAMETER
#define FLASH_ERASE_UNLOCK_CODE0 0x72
#define FLASH_ERASE_UNLOCK_CODE1 0x03
#define FLASH_ERASE_UNLOCK_CODE2 0x02
#define FLASH_ERASE_CODE0 0x02
#define FLASH_ERASE_CODE1 0xC0
#define FLASH_DMA_CODE0 0x05
#define FLASH_DMA_CODE1 0xC0
#define FLASH_DMA_CONFIG 0x06
#define FLASH_ERASE_START 0x80
#define FLASH_NUM_PAGE 64//number of pages
#define FLASH_CX_PAGE_START 61
#define FLASH_CX_PAGE_END 62
#endif
//FLASH ADDRESS
#ifdef FTM3_CHIP
#define FLASH_ADDR_SWITCH_CMD 0x00010000
#define FLASH_ADDR_CODE 0x00000000
#define FLASH_ADDR_CONFIG 0x0001E800
#define FLASH_ADDR_CX 0x0001F000
#else
#define ADDR_WARM_BOOT 0x001E
#define WARM_BOOT_VALUE 0x38
#define FLASH_ADDR_CODE 0x00000000
#define FLASH_ADDR_CONFIG 0x0000FC00
#endif
//CRC ADDR
#ifdef FTM3_CHIP
#define ADDR_CRC_BYTE0 0x00
#define ADDR_CRC_BYTE1 0x86
#define CRC_MASK 0x02
#else
#define ADDR_CRC_BYTE0 0x00
#define ADDR_CRC_BYTE1 0x74
#define CRC_MASK 0x03
#endif
//SIZES FW, CODE, CONFIG, MEMH
#ifdef FTM3_CHIP
#define FW_HEADER_SIZE 32
#define FW_SIZE (int)(128*1024)
#define FW_CODE_SIZE (int)(122*1024)
#define FW_CONFIG_SIZE (int)(2*1024)
#define FW_CX_SIZE (int)(FW_SIZE-FW_CODE_SIZE-FW_CONFIG_SIZE)
#define FW_VER_MEMH_BYTE1 193
#define FW_VER_MEMH_BYTE0 192
#define FW_OFF_CONFID_MEMH_BYTE1 2
#define FW_OFF_CONFID_MEMH_BYTE0 1
#define FW_BIN_VER_OFFSET 4
#define FW_BIN_CONFIG_VER_OFFSET (FW_HEADER_SIZE+FW_CODE_SIZE+1)
#else
#define FW_HEADER_SIZE 64
#define FW_HEADER_SIGNATURE 0xAA55AA55
#define FW_FTB_VER 0x00000001
#define FW_BYTES_ALIGN 4
#define FW_BIN_VER_OFFSET 16
#define FW_BIN_CONFIG_VER_OFFSET 20
#endif
//FIFO
#define FIFO_EVENT_SIZE 8
#ifdef FTM3_CHIP
#define FIFO_DEPTH 32
#else
#define FIFO_DEPTH 64
#endif
#define FIFO_CMD_READONE 0x85
#define FIFO_CMD_READALL 0x86
#define FIFO_CMD_LAST 0x87
#define FIFO_CMD_FLUSH 0xA1
//CONSTANT TOTAL CX
#ifdef FTM3_CHIP
#define CX1_WEIGHT 4
#define CX2_WEIGHT 1
#else
#define CX1_WEIGHT 8
#define CX2_WEIGHT 1
#endif
//OP CODES FOR MEMORY (based on protocol)
#define FTS_CMD_HW_REG_R 0xB6
#define FTS_CMD_HW_REG_W 0xB6
#define FTS_CMD_FRAMEBUFFER_R 0xD0
#define FTS_CMD_FRAMEBUFFER_W 0xD0
#endif

View file

@ -0,0 +1,526 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* I2C/SPI Communication **
* *
**************************************************************************
**************************************************************************
*
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/spi/spidev.h>
#include <linux/timekeeping.h>
#include "ftsSoftware.h"
#include "ftsCrossCompile.h"
#include "ftsError.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsTool.h"
#include "../fts.h"
static char tag[8] = "[ FTS ]\0";
static struct i2c_client *client;
static u16 I2CSAD;
int openChannel(struct i2c_client *clt)
{
client = clt;
I2CSAD = clt->addr;
logError(0, "%s %s: SAD: %02X\n", tag, __func__, I2CSAD);
return OK;
}
struct device *getDev()
{
if (client != NULL)
return &(client->dev);
else
return NULL;
}
struct i2c_client *getClient()
{
if (client != NULL)
return client;
else
return NULL;
}
int fts_readCmd(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
{
int ret = -1;
int retry = 0;
struct i2c_msg I2CMsg[2];
struct fts_ts_info *info = i2c_get_clientdata(client);
uint8_t *buf = info->i2c_data;
/*
* Reassign memory for i2c_data in case length is greater than 32 bytes
*/
if (info->i2c_data_len < cmdLength + byteToRead + 1) {
kfree(info->i2c_data);
info->i2c_data = kmalloc(cmdLength + byteToRead + 1,
GFP_KERNEL);
if (!info->i2c_data) {
info->i2c_data_len = 0;
return -ENOMEM;
}
info->i2c_data_len = cmdLength + byteToRead + 1;
buf = info->i2c_data;
}
//write msg
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = buf;
//read msg
I2CMsg[1].addr = (__u16)I2CSAD;
I2CMsg[1].flags = I2C_M_RD;
I2CMsg[1].len = byteToRead;
I2CMsg[1].buf = buf + cmdLength;
memcpy(buf, cmd, cmdLength);
if (client == NULL)
return ERROR_I2C_O;
while (retry < I2C_RETRY && ret < OK) {
ret = i2c_transfer(client->adapter, I2CMsg, 2);
retry++;
if (ret < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
return ERROR_I2C_R;
}
memcpy(outBuf, buf + cmdLength, byteToRead);
return OK;
}
int fts_writeCmd(u8 *cmd, int cmdLength)
{
int ret = -1;
int retry = 0;
struct i2c_msg I2CMsg[1];
struct fts_ts_info *info = i2c_get_clientdata(client);
uint8_t *buf = info->i2c_data;
/*
* Reassign memory for i2c_data in case length is greater than 32 bytes
*/
if (info->i2c_data_len < cmdLength + 1) {
kfree(info->i2c_data);
info->i2c_data = kmalloc(cmdLength + 1, GFP_KERNEL);
if (!info->i2c_data) {
info->i2c_data_len = 0;
return -ENOMEM;
}
info->i2c_data_len = cmdLength + 1;
buf = info->i2c_data;
}
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = buf;
memcpy(buf, cmd, cmdLength);
if (client == NULL)
return ERROR_I2C_O;
while (retry < I2C_RETRY && ret < OK) {
ret = i2c_transfer(client->adapter, I2CMsg, 1);
retry++;
if (ret < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
//logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
}
return OK;
}
int fts_writeFwCmd(u8 *cmd, int cmdLength)
{
int ret = -1;
int ret2 = -1;
int retry = 0;
struct i2c_msg I2CMsg[1];
struct fts_ts_info *info = i2c_get_clientdata(client);
uint8_t *buf = info->i2c_data;
/*
* Reassign memory for i2c_data in case length is greater than 32 bytes
*/
if (info->i2c_data_len < cmdLength + 1) {
kfree(info->i2c_data);
info->i2c_data = kmalloc(cmdLength + 1, GFP_KERNEL);
if (!info->i2c_data) {
info->i2c_data_len = 0;
return -ENOMEM;
}
info->i2c_data_len = cmdLength + 1;
buf = info->i2c_data;
}
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = buf;
memcpy(buf, cmd, cmdLength);
if (client == NULL)
return ERROR_I2C_O;
while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) {
ret = i2c_transfer(client->adapter, I2CMsg, 1);
retry++;
if (ret >= 0)
ret2 = checkEcho(cmd, cmdLength);
if (ret < OK || ret2 < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
//logError(1,"%s fts_writeCmd: attempt %d\n", tag, retry);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_W);
return ERROR_I2C_W;
}
if (ret2 < OK) {
logError(1, "%s %s: check echo ERROR %02X\n",
tag, __func__, ret2);
return (ret | ERROR_I2C_W);
}
return OK;
}
int writeReadCmd(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1,
int readCmdLength, u8 *outBuf, int byteToRead)
{
int ret = -1;
int retry = 0;
struct i2c_msg I2CMsg[3];
struct fts_ts_info *info = i2c_get_clientdata(client);
uint8_t *buf = info->i2c_data;
uint8_t wr_len = writeCmdLength + readCmdLength + byteToRead;
/*
* Reassign memory for i2c_data in case length is greater than 32 bytes
*/
if (info->i2c_data_len < wr_len + 1) {
kfree(info->i2c_data);
info->i2c_data = kmalloc(wr_len + 1, GFP_KERNEL);
if (!info->i2c_data) {
info->i2c_data_len = 0;
return -ENOMEM;
}
info->i2c_data_len = wr_len + 1;
buf = info->i2c_data;
}
//write msg
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)writeCmdLength;
I2CMsg[0].buf = buf;
//write msg
I2CMsg[1].addr = (__u16)I2CSAD;
I2CMsg[1].flags = (__u16)0;
I2CMsg[1].len = (__u16)readCmdLength;
I2CMsg[1].buf = buf + writeCmdLength;
//read msg
I2CMsg[2].addr = (__u16)I2CSAD;
I2CMsg[2].flags = I2C_M_RD;
I2CMsg[2].len = byteToRead;
I2CMsg[2].buf = buf + writeCmdLength + readCmdLength;
memcpy(buf, writeCmd1, writeCmdLength);
memcpy(buf + writeCmdLength, readCmd1, readCmdLength);
if (client == NULL)
return ERROR_I2C_O;
while (retry < I2C_RETRY && ret < OK) {
ret = i2c_transfer(client->adapter, I2CMsg, 3);
retry++;
if (ret < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_WR);
return ERROR_I2C_WR;
}
memcpy(outBuf, buf + writeCmdLength + readCmdLength, byteToRead);
return OK;
}
int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead,
int hasDummyByte)
{
int remaining = byteToRead;
int toRead = 0;
u8 rCmd[3] = { cmd, 0x00, 0x00 };
u8 *buff = (u8 *)kmalloc_array(READ_CHUNK + 1, sizeof(u8), GFP_KERNEL);
if (buff == NULL) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
while (remaining > 0) {
if (remaining >= READ_CHUNK) {
toRead = READ_CHUNK;
remaining -= READ_CHUNK;
} else {
toRead = remaining;
remaining = 0;
}
rCmd[1] = (u8)((address & 0xFF00) >> 8);
rCmd[2] = (u8)(address & 0xFF);
if (hasDummyByte) {
if (fts_readCmd(rCmd, 3, buff, toRead + 1) < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_R);
kfree(buff);
return ERROR_I2C_R;
}
memcpy(outBuf, buff + 1, toRead);
} else {
if (fts_readCmd(rCmd, 3, buff, toRead) < 0)
return ERROR_I2C_R;
memcpy(outBuf, buff, toRead);
}
address += toRead;
outBuf += toRead;
}
kfree(buff);
return OK;
}
int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite)
{
int remaining = byteToWrite;
int toWrite = 0;
u8 *buff = (u8 *)kmalloc_array(WRITE_CHUNK + 3, sizeof(u8), GFP_KERNEL);
if (buff == NULL) {
logError(1, "%s %s: ERROR %02X\n", tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
buff[0] = WriteCmd;
while (remaining > 0) {
if (remaining >= WRITE_CHUNK) {
toWrite = WRITE_CHUNK;
remaining -= WRITE_CHUNK;
} else {
toWrite = remaining;
remaining = 0;
}
buff[1] = (u8)((address & 0xFF00) >> 8);
buff[2] = (u8)(address & 0xFF);
memcpy(buff + 3, dataToWrite, toWrite);
if (fts_writeCmd(buff, 3 + toWrite) < 0) {
logError(1, "%s %s: ERROR %02\n",
tag, __func__, ERROR_I2C_W);
kfree(buff);
return ERROR_I2C_W;
}
address += toWrite;
dataToWrite += toWrite;
}
kfree(buff);
return OK;
}
int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite,
int byteToWrite)
{
int remaining = byteToWrite;
int toWrite = 0;
int ret;
u8 buff1[3] = { writeCmd1, 0x00, 0x00 };
u8 *buff2 = (u8 *)kmalloc_array(WRITE_CHUNK + 3,
sizeof(u8), GFP_KERNEL);
if (buff2 == NULL) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
buff2[0] = writeCmd2;
while (remaining > 0) {
if (remaining >= WRITE_CHUNK) {
toWrite = WRITE_CHUNK;
remaining -= WRITE_CHUNK;
} else {
toWrite = remaining;
remaining = 0;
}
buff1[1] = (u8)((address & 0xFF000000) >> 24);
buff1[2] = (u8)((address & 0x00FF0000) >> 16);
buff2[1] = (u8)((address & 0x0000FF00) >> 8);
buff2[2] = (u8)(address & 0xFF);
memcpy(buff2 + 3, dataToWrite, toWrite);
if (fts_writeCmd(buff1, 3) < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_W);
ret = ERROR_I2C_W;
goto END;
}
if (fts_writeCmd(buff2, 3 + toWrite) < 0) {
logError(1, "%s %s: ERROR %02X\n",
tag, __func__, ERROR_I2C_W);
ret = ERROR_I2C_W;
goto END;
}
address += toWrite;
dataToWrite += toWrite;
}
ret = OK;
END:
kfree(buff2);
return ret;
}
int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf,
int byteToRead, int hasDummyByte)
{
int remaining = byteToRead;
int toRead = 0;
u8 reaCmd[3];
u8 wriCmd[3];
u8 *buff = (u8 *)kmalloc_array(READ_CHUNK + 1, sizeof(u8), GFP_KERNEL);
if (buff == NULL) {
logError(1, "%s writereadCmd32: ERROR %02X\n",
tag, ERROR_ALLOC);
return ERROR_ALLOC;
}
reaCmd[0] = rCmd;
wriCmd[0] = wCmd;
while (remaining > 0) {
if (remaining >= READ_CHUNK) {
toRead = READ_CHUNK;
remaining -= READ_CHUNK;
} else {
toRead = remaining;
remaining = 0;
}
wriCmd[1] = (u8)((address & 0xFF000000) >> 24);
wriCmd[2] = (u8)((address & 0x00FF0000) >> 16);
reaCmd[1] = (u8)((address & 0x0000FF00) >> 8);
reaCmd[2] = (u8)(address & 0x000000FF);
if (hasDummyByte) {
if (writeReadCmd(wriCmd, 3, reaCmd, 3,
buff, toRead + 1) < 0) {
logError(1, "%s writeCmdU32: ERROR %02X\n",
tag, ERROR_I2C_WR);
kfree(buff);
return ERROR_I2C_WR;
}
memcpy(outBuf, buff + 1, toRead);
} else {
if (writeReadCmd(wriCmd, 3, reaCmd,
3, buff, toRead) < 0)
return ERROR_I2C_WR;
memcpy(outBuf, buff, toRead);
}
address += toRead;
outBuf += toRead;
}
kfree(buff);
return OK;
}

View file

@ -0,0 +1,64 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* I2C/SPI Communication **
* *
**************************************************************************
**************************************************************************
*/
#ifndef __FTS_IO_H
#define __FTS_IO_H
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "ftsSoftware.h"
#include "ftsCrossCompile.h"
#define I2C_RETRY 3 //number of retry
#define I2C_WAIT_BEFORE_RETRY 2 //ms
int openChannel(struct i2c_client *clt);
struct device *getDev(void);
struct i2c_client *getClient(void);
int fts_readCmd(u8 *cmd, int cmdLenght, u8 *outBuf, int byteToRead);
int fts_writeCmd(u8 *cmd, int cmdLenght);
int fts_writeFwCmd(u8 *cmd, int cmdLenght);
int writeReadCmd(u8 *writeCmd, int writeCmdLenght, u8 *readCmd,
int readCmdLenght, u8 *outBuf, int byteToRead);
int readCmdU16(u8 cmd, u16 address, u8 *outBuf, int byteToRead,
int hasDummyByte);
int writeCmdU16(u8 WriteCmd, u16 address, u8 *dataToWrite, int byteToWrite);
int writeCmdU32(u8 writeCmd1, u8 writeCmd2, u32 address, u8 *dataToWrite,
int byteToWrite);
int writeReadCmdU32(u8 wCmd, u8 rCmd, u32 address, u8 *outBuf, int byteToRead,
int hasDummyByte);
#endif

View file

@ -0,0 +1,191 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FW related data *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_SOFTWARE_H
#define __FTS_SOFTWARE_H
#include <linux/types.h>
#include "ftsHardware.h"
#define ECHO_ENABLED 0x00000001
//FTS FW COMMAND
#define FTS_CMD_MS_MT_SENSE_OFF 0x92
#define FTS_CMD_MS_MT_SENSE_ON 0x93
#define FTS_CMD_SS_HOVER_OFF 0x94
#define FTS_CMD_SS_HOVER_ON 0x95
#define FTS_CMD_LP_TIMER_CALIB 0x97
#define FTS_CMD_MS_KEY_OFF 0x9A
#define FTS_CMD_MS_KEY_ON 0x9B
#define FTS_CMD_MS_COMP_TUNING 0xA3
#define FTS_CMD_SS_COMP_TUNING 0xA4
#define FTS_CMD_FULL_INITIALIZATION 0xA5
#define FTS_CMD_ITO_CHECK 0xA7
#define FTS_CMD_RELEASE_INFO 0xAA
#define FTS_CMD_GESTURE_MODE 0xAD
#define FTS_CMD_REQU_FW_CONF 0xB2
#define FTS_CMD_REQU_FRAME_DATA 0xB7
#define FTS_CMD_REQU_COMP_DATA 0xB8
#define FTS_CMD_WRITE_MP_FLAG 0xC0
#define FTS_CMD_FEATURE_ENABLE 0xC1
#define FTS_CMD_FEATURE_DISABLE 0xC2
#define FTS_CMD_GESTURE_CMD 0xC3
#define FTS_CMD_LOCKDOWN_CMD 0xC4
#define FTS_CMD_NOISE_WRITE 0xC7
#define FTS_CMD_NOISE_READ 0xC8
#define FTS_CMD_LOCKDOWN_FILL 0xCA
#define FTS_CMD_LOCKDOWN_WRITE 0xCB
#define FTS_CMD_LOCKDOWN_READ 0xCC
#define FTS_CMD_SAVE_CX_TUNING 0xFC
//Event ID
#define EVENTID_NO_EVENT 0x00
#define EVENTID_ERROR_EVENT 0x0F
#define EVENTID_CONTROL_READY 0x10
#define EVENTID_FW_CONFIGURATION 0x12
#define EVENTID_COMP_DATA_READ 0x13
#define EVENTID_STATUS_UPDATE 0x16
#define EVENTID_RELEASE_INFO 0x1C
#define EVENTID_LOCKDOWN_INFO 0x1E
#define EVENTID_ENTER_POINTER 0x03
#define EVENTID_LEAVE_POINTER 0x04
#define EVENTID_MOTION_POINTER 0x05
#define EVENTID_HOVER_ENTER_POINTER 0x07
#define EVENTID_HOVER_LEAVE_POINTER 0x08
#define EVENTID_HOVER_MOTION_POINTER 0x09
#define EVENTID_PROXIMITY_ENTER 0x0B
#define EVENTID_PROXIMITY_LEAVE 0x0C
#define EVENTID_KEY_STATUS 0x0E
#define EVENTID_LOCKDOWN_INFO_READ 0x1E
#define EVENTID_NOISE_READ 0x17
#define EVENTID_NOISE_WRITE 0x18
#define EVENTID_GESTURE 0x22
#define EVENTID_FRAME_DATA_READ 0x25
#define EVENTID_ECHO 0xEC
#define EVENTID_LAST (EVENTID_FRAME_DATA_READ+1)
//EVENT TYPE
#define EVENT_TYPE_MS_TUNING_CMPL 0x01
#define EVENT_TYPE_SS_TUNING_CMPL 0x02
#define EVENT_TYPE_COMP_DATA_SAVED 0x04
#define EVENT_TYPE_ITO 0x05
#define EVENT_TYPE_FULL_INITIALIZATION 0x07
#define EVENT_TYPE_LPTIMER_TUNING_CMPL 0x20
#define EVENT_TYPE_ESD_ERROR 0x0A
#define EVENT_TYPE_WATCHDOG_ERROR 0x01
#define EVENT_TYPE_CHECKSUM_ERROR 0x03
#define EVENT_TYPE_LOCKDOWN 0x0A
#define EVENT_TYPE_LOCKDOWN_WRITE 0x08
#define EVENT_TYPE_LOCKDOWN_ERROR 0x0B
//CRC type
#define CRC_CONFIG_SIGNATURE 0x01
#define CRC_CONFIG 0x02
#define CRC_CX_MEMORY 0x03
// CONFIG ID INFO
#define CONFIG_ID_ADDR 0x0001
#define CONFIG_ID_BYTE 2
//ADDRESS OFFSET IN SYSINFO
#define ADDR_RAW_TOUCH 0x0000
#define ADDR_FILTER_TOUCH 0x0002
#define ADDR_NORM_TOUCH 0x0004
#define ADDR_CALIB_TOUCH 0x0006
#define ADDR_RAW_HOVER_FORCE 0x000A
#define ADDR_RAW_HOVER_SENSE 0x000C
#define ADDR_FILTER_HOVER_FORCE 0x000E
#define ADDR_FILTER_HOVER_SENSE 0x0010
#define ADDR_NORM_HOVER_FORCE 0x0012
#define ADDR_NORM_HOVER_SENSE 0x0014
#define ADDR_CALIB_HOVER_FORCE 0x0016
#define ADDR_CALIB_HOVER_SENSE 0x0018
#define ADDR_RAW_PRX_FORCE 0x001A
#define ADDR_RAW_PRX_SENSE 0x001C
#define ADDR_FILTER_PRX_FORCE 0x001E
#define ADDR_FILTER_PRX_SENSE 0x0020
#define ADDR_NORM_PRX_FORCE 0x0022
#define ADDR_NORM_PRX_SENSE 0x0024
#define ADDR_CALIB_PRX_FORCE 0x0026
#define ADDR_CALIB_PRX_SENSE 0x0028
#define ADDR_RAW_MS_KEY 0x0032
#define ADDR_NORM_MS_KEY 0x0036
#define ADDR_COMP_DATA 0x0050
#define ADDR_FRAMEBUFFER_DATA 0x8000
//ADDRESS FW REGISTER
#define ADDR_SENSE_LEN 0x0014
#define ADDR_FORCE_LEN 0x0015
#define ADDR_MS_TUNING_VER 0x0729
#define ADDR_SS_TUNING_VER 0x074E
//B2 INFO
#define B2_DATA_BYTES 4
//number of bytes
#define B2_CHUNK ((FIFO_DEPTH/2)*B2_DATA_BYTES)
//FEATURES
#define FEAT_GLOVE 0x00000001
#define FEAT_STYLUS 0x00000002
#define FEAT_COVER 0x00000004
#define FEAT_CHARGER 0x00000008
#define FEAT_VR 0x00000010
#define FEAT_EDGE_REJECTION 0x00000020
#define FEAT_CORNER_REJECTION 0x00000040
#define FEAT_EDGE_PALM_REJECTION 0x00000100
//TOUCH SIZE
#define STYLUS_SIZE 0x01
#define FINGER_SIZE 0x02
#define LARGE_SIZE 0x03
//C7/C8 parameters
#define NOISE_PARAMETERS 0x01
//MP_FLAG_VALUE
#define INIT_MP 0xA5A5A501
#define INIT_FIELD 0xA5A5A502
//NOISE PARAMS
#define NOISE_PARAMETERS_SIZE 4 //bytes
//ERROR INFO
#define ERROR_INFO_SIZE (20*4) // bytes
#define ERROR_SIGNATURE 0xFA5005AF
#define ERROR_SIGN_HEAD 0xA5
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,193 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS API for MP test **
* *
**************************************************************************
**************************************************************************
*/
#ifndef __FTS_TEST_H
#define __FTS_TEST_H
#include "ftsSoftware.h"
#define LIMITS_FILE "stm_fts_production_limits.csv"
#define WAIT_FOR_FRESH_FRAMES 100 //ms
#define WAIT_AFTER_SENSEOFF 50 //ms
#define TIMEOUT_ITO_TEST_RESULT 200 //ms
#define TIMEOUT_INITIALIZATION_TEST_RESULT 5000 //ms
//LABELS PRODUCTION TEST LIMITS FILE
#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX"
#define MS_RAW_GAP "MS_RAW_DATA_GAP"
#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX"
#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN"
#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX"
#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN"
#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX"
#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX"
#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX"
#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP"
#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP"
#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX"
#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX"
#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX"
#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX"
#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN"
#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX"
#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN"
#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX"
#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL"
#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL"
#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN"
#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX"
#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN"
#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX"
#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL"
#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL"
// TOTAL SS
#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN"
#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX"
#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN"
#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX"
#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL"
#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL"
#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN"
#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX"
#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN"
#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX"
#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL"
#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL"
//KEYS
#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX"
#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX"
#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN"
#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX"
#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN"
#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX"
//CONSTANT TOTAL IX
#define SS_IX1_FORCE_W "IX1_FORCE_W"
#define SS_IX2_FORCE_W "IX2_FORCE_W"
#define SS_IX1_SENSE_W "IX1_SENSE_W"
#define SS_IX2_SENSE_W "IX2_SENSE_W"
#define SAVE_FLAG_RETRY 3
struct TestToDo {
int MutualRaw;
int MutualRawGap;
int MutualCx1;
int MutualCx2;
int MutualCx2Adj;
int MutualCxTotal;
int MutualCxTotalAdj;
int MutualKeyRaw;
int MutualKeyCx1;
int MutualKeyCx2;
int MutualKeyCxTotal;
int SelfForceRaw;
int SelfForceRawGap;
int SelfForceIx1;
int SelfForceIx2;
int SelfForceIx2Adj;
int SelfForceIxTotal;
int SelfForceIxTotalAdj;
int SelfForceCx1;
int SelfForceCx2;
int SelfForceCx2Adj;
int SelfForceCxTotal;
int SelfForceCxTotalAdj;
int SelfSenseRaw;
int SelfSenseRawGap;
int SelfSenseIx1;
int SelfSenseIx2;
int SelfSenseIx2Adj;
int SelfSenseIxTotal;
int SelfSenseIxTotalAdj;
int SelfSenseCx1;
int SelfSenseCx2;
int SelfSenseCx2Adj;
int SelfSenseCxTotal;
int SelfSenseCxTotalAdj;
};
int computeAdjHoriz(u8 *data, int row, int column, u8 **result);
int computeAdjHorizTotal(u16 *data, int row, int column, u16 **result);
int computeAdjVert(u8 *data, int row, int column, u8 **result);
int computeAdjVertTotal(u16 *data, int row, int column, u16 **result);
int computeTotal(u8 *data, u8 main, int row, int column, int m,
int n, u16 **result);
int checkLimitsMinMax(short *data, int row, int column, int min, int max);
int checkLimitsMap(u8 *data, int row, int column, int *min, int *max);
int checkLimitsMapTotal(u16 *data, int row, int column, int *min, int *max);
int checkLimitsMapAdj(u8 *data, int row, int column, int *max);
int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max);
int production_test_ito(void);
int production_test_initialization(void);
int ms_compensation_tuning(void);
int ss_compensation_tuning(void);
int lp_timer_calibration(void);
int save_cx_tuning(void);
int production_test_split_initialization(int saveToFlash);
int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit,
struct TestToDo *todo, u32 signature);
int production_test_ms_raw(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_ms_cx(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_ss_raw(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_ss_ix_cx(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_data(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_ms_key_cx(char *path_limits, int stop_on_fail,
struct TestToDo *todo);
int production_test_ms_key_raw(char *path_limits);
int save_mp_flag(u32 signature);
int parseProductionTestLimits(char *path, char *label, int **data,
int *row, int *column);
int readLine(char *data, char *line, int size, int *n);
#endif

View file

@ -0,0 +1,109 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility for mesuring/handling the time *
* *
**************************************************************************
***************************************************************************
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/power_supply.h>
#include <linux/firmware.h>
#include <linux/regulator/consumer.h>
#include <linux/of_gpio.h>
#include <linux/timekeeping.h>
//#include <linux/sec_sysfs.h>
#include "ftsCrossCompile.h"
#include "ftsTime.h"
void startStopWatch(struct StopWatch *w)
{
ktime_get_ts(&w->start);
}
void stopStopWatch(struct StopWatch *w)
{
ktime_get_ts(&w->end);
}
int elapsedMillisecond(struct StopWatch *w)
{
int result;
result = ((w->end.tv_sec - w->start.tv_sec) * 1000)
+ (w->end.tv_nsec - w->start.tv_nsec) / 1000000;
return result;
}
int elapsedNanosecond(struct StopWatch *w)
{
int result;
result = ((w->end.tv_sec - w->start.tv_sec) * 1000000000)
+ (w->end.tv_nsec - w->start.tv_nsec);
return result;
}
char *timestamp()
{
char *result = NULL;
result = (char *)kmalloc_array(1, sizeof(char), GFP_KERNEL);
if (result == NULL)
return NULL;
result[0] = ' ';
return result;
}
void stdelay(unsigned long ms)
{
msleep(ms);
}

View file

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility for mesuring/handling the time *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_TIME_H
#define __FTS_TIME_H
#include <linux/time.h>
#include "ftsCrossCompile.h"
struct StopWatch {
struct timespec start, end;
};
void startStopWatch(struct StopWatch *w);
void stopStopWatch(struct StopWatch *w);
int elapsedMillisecond(struct StopWatch *w);
int elapsedNanosecond(struct StopWatch *w);
char *timestamp(void);
void stdelay(unsigned long ms);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2016-2019, STMicroelectronics Limited.
* Authors: AMG(Analog Mems Group) <marco.cali@st.com>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility Functions *
* *
**************************************************************************
**************************************************************************
*
*/
#ifndef __FTS_TOOL_H
#define __FTS_TOOL_H
#define GPIO_NOT_DEFINED -1
#define TIMEOUT_RESOLUTION 10 //ms
#define GENERAL_TIMEOUT (50*TIMEOUT_RESOLUTION) //ms
#define RELEASE_INFO_TIMEOUT (15*TIMEOUT_RESOLUTION) //ms
#define FEAT_ENABLE 1
#define FEAT_DISABLE 0
#define SYSTEM_RESET_RETRY 3
#define B2_RETRY 2
//for FTM4 can not be greater than 13 bytes
#define LOCKDOWN_CODE_SIZE 10
#define LOCKDOWN_CODE_MAX_SIZE 63
#define LOCKDOWN_CODE_WRITE_CHUNK 12
#define LOCKDOWN_CODE_READ_CHUNK 4
#define LOCKDOWN_CODE_RETRY 2
int readB2(u16 address, u8 *outBuf, int len);
int readB2U16(u16 address, u8 *outBuf, int byteToRead);
int releaseInformation(void);
int lockDownInfo(u8 *data, int len);
int calculateCRC8(u8 *u8_srcBuff, int size, u8 *crc);
int writeLockDownInfo(u8 *data, int size);
int rewriteLockDownInfo(u8 *data, int size);
int readLockDownInfo(u8 *lockData, int *size);
char *printHex(char *label, u8 *buff, int count);
int pollForEvent(int *event_to_search, int event_bytes,
u8 *readData, int time_to_wait);
int fts_disableInterrupt(void);
int fts_enableInterrupt(void);
int u8ToU16(u8 *src, u16 *dst);
int u8ToU16_le(u8 *src, u16 *dst);
int u8ToU16n(u8 *src, int src_length, u16 *dst);
int u16ToU8(u16 src, u8 *dst);
int u16ToU8_le(u16 src, u8 *dst);
int u16ToU8_be(u16 src, u8 *dst);
int u16ToU8n(u16 *src, int src_length, u8 *dst);
int u8ToU32(u8 *src, u32 *dst);
int u32ToU8(u32 src, u8 *dst);
int attempt_function(int(*code)(void), unsigned long wait_before_retry,
int retry_count);
void setResetGpio(int gpio);
int fts_system_reset(void);
int isSystemResettedUp(void);
int isSystemResettedDown(void);
void setSystemResettedUp(int val);
void setSystemResettedDown(int val);
int senseOn(void);
int senseOff(void);
int keyOn(void);
int keyOff(void);
int featureEnableDisable(int on_off, u32 feature);
int writeNoiseParameters(u8 *noise);
int readNoiseParameters(u8 *noise);
int checkEcho(u8 *cmd, int size);
void print_frame_short(char *label, short **matrix, int row, int column);
short **array1dTo2d_short(short *data, int size, int columns);
u8 **array1dTo2d_u8(u8 *data, int size, int columns);
void print_frame_u8(char *label, u8 **matrix, int row, int column);
void print_frame_u32(char *label, u32 **matrix, int row, int column);
void print_frame_int(char *label, int **matrix, int row, int column);
int cleanUp(int enableTouch);
int flushFIFO(void);
#endif