fts: initial STmicro touch driver code

Initial driver code v5.2.18

Change-Id: I1da8b0a36dbd147fee08e2ffba5d175113296c83
Signed-off-by: Konstantin Makariev <hcv867@motorola.com>
Reviewed-on: https://gerrit.mot.com/1682343
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Konstantin Makariev <kmakariev@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
Konstantin Makariev 2020-07-14 10:44:41 -05:00 • committed by Konstantin Makariev
commit 366e3815d0
29 changed files with 38585 additions and 0 deletions

View file

@ -0,0 +1,6 @@
#
# Makefile for the touchscreen drivers.
#
obj-y += fts.o fts_proc.o fts_lib/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,355 @@
/*
* fts.c
*
* FTS Capacitive touch screen controller (FingerTipS)
*
* Copyright (C) 2017, STMicroelectronics
* 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.
*
* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE
* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM
*THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS.
*/
/*!
* \file fts.h
* \brief Contains all the definitions and structs used generally by the driver
*/
#ifndef _LINUX_FTS_I2C_H_
#define _LINUX_FTS_I2C_H_
#include <linux/device.h>
#include "fts_lib/ftsSoftware.h"
#include "fts_lib/ftsHardware.h"
/****************** CONFIGURATION SECTION ******************/
/** @defgroup conf_section Driver Configuration Section
* Settings of the driver code in order to suit the HW set up and the
*application behavior
* @{
*/
/* **** CODE CONFIGURATION **** */
#define FTS_TS_DRV_NAME "fts" /* /< driver name */
#define FTS_TS_DRV_VERSION "5.2.18" /* /< driver version string format */
#define FTS_TS_DRV_VER 0x05021200 /* driver version u32 format */
#define DEBUG /* /< define to print more logs in the kernel log and better
* follow the code flow */
#define DRIVER_TEST /* /< if defined allow to use and test special functions
* of the driver and fts_lib from comand shell (usefull
* for enginering/debug operations) */
/* If both COMPUTE_INIT_METHOD and PRE_SAVED_METHOD are not defined,
* driver will be automatically configured as GOLDEN_VALUE_METHOD */
/*#define COMPUTE_INIT_METHOD*/ /* Allow to compute init data on phone during
production */
#ifndef COMPUTE_INIT_METHOD
#define PRE_SAVED_METHOD /* Pre-Saved Method used
* during production */
#endif
/* #define FW_H_FILE */ /* include the FW data as header file */
#ifdef FW_H_FILE
#define FW_SIZE_NAME myArray_size /* /< name of the variable in
* the FW header file which
* specified the dimension of
* the FW data array */
#define FW_ARRAY_NAME myArray /* /< name of the variable in the FW
* header file which specified the FW
* data array */
/* #define FW_UPDATE_ON_PROBE */
/* if defined the FW update will be execute on the probe, if not it will be
* executed EXP_FN_WORK_DELAY_MS ms after the probe is completed */
#endif
#ifndef FW_UPDATE_ON_PROBE
/* #define LIMITS_H_FILE */
/* include the Production Limit File as header file, can be commented to use a
* .csv file instead */
#ifdef LIMITS_H_FILE
#define LIMITS_SIZE_NAME myArray2_size /* /< name of the
* variable in the
* limits header file
* which specified the
* dimension of the
* limits data array */
#define LIMITS_ARRAY_NAME myArray2 /* /< name of the
* variable in the
* limits header file
* which specified the
* limits data array */
#endif
#else
/* if execute fw update in the probe the limit file must be a .h */
#define LIMITS_H_FILE /* /< include the Production Limit File as header file,
* DO NOT COMMENT! */
#define LIMITS_SIZE_NAME myArray2_size /* /< name of the
* variable in the
* limits header file
* which specified the
* dimension of the
* limits data array */
#define LIMITS_ARRAY_NAME myArray2 /* /< name of the
* variable in the
* limits header file
* which specified the
* limits data array */
#endif
#define USE_ONE_FILE_NODE
/* allow to enable/disable all the features just using one file node */
#ifndef FW_UPDATE_ON_PROBE
#define EXP_FN_WORK_DELAY_MS 1000 /* /< time in ms elapsed after the probe
* to start the work which execute FW
* update and the Initialization of the
* IC */
#endif
/* **** END **** */
/* **** FEATURES USED IN THE IC **** */
/* Enable the support of keys */
/* #define PHONE_KEY */
#define GESTURE_MODE /* /< enable the support of the gestures */
#ifdef GESTURE_MODE
#define USE_GESTURE_MASK /* /< the gestures to select are
* referred using a gesture bitmask
* instead of their gesture IDs */
#endif
#define CHARGER_MODE /* /< enable the support to charger mode feature
* (comment to disable) */
#define GLOVE_MODE /* /< enable the support to glove mode feature (comment
* to disable) */
#define COVER_MODE /* /< enable the support to cover mode feature (comment
* to disable) */
#define STYLUS_MODE /* /< enable the support to stylus mode feature (comment
* to disable) */
#define GRIP_MODE /* /< enable the support to grip mode feature (comment
* to disable) */
/* **** END **** */
/* **** PANEL SPECIFICATION **** */
#define X_AXIS_MAX 1440 /* /< Max X coordinate of the display */
#define X_AXIS_MIN 0 /* /< min X coordinate of the display */
#define Y_AXIS_MAX 2959 /* /< Max Y coordinate of the display */
#define Y_AXIS_MIN 0 /* /< min Y coordinate of the display */
#define PRESSURE_MIN 0 /* /< min value of pressure reported */
#define PRESSURE_MAX 127 /* /< Max value of pressure reported */
#define DISTANCE_MIN 0 /* /< min distance between the tool and the
* display */
#define DISTANCE_MAX 127 /* /< Max distance between the tool and the
* display */
#define TOUCH_ID_MAX 10 /* /< Max number of simoultaneous touches
* reported */
#define AREA_MIN PRESSURE_MIN /* /< min value of Major/minor axis
* reported */
#define AREA_MAX PRESSURE_MAX /* /< Man value of Major/minor axis
* reported */
/* **** END **** */
/**@}*/
/*********************************************************/
/*
* Configuration mode
*
* bitmask which can assume the value defined as features in ftsSoftware.h or
* the following values
*/
/** @defgroup mode_section IC Status Mode
* Bitmask which keeps track of the features and working mode enabled in the
* IC.
* The meaning of the the LSB of the bitmask must be interpreted considering
* that the value defined in @link feat_opt Feature Selection Option @endlink
* correspond to the position of the corresponding bit in the mask
* @{
*/
#define MODE_NOTHING 0x00000000 /* /< nothing enabled (sense off) */
#define MODE_ACTIVE(_mask, _sett) (_mask |= (SCAN_MODE_ACTIVE << 24) | \
(_sett << 16))
/* /< store the status of scan mode active and its setting */
#define MODE_LOW_POWER(_mask, _sett) (_mask |= (SCAN_MODE_LOW_POWER << 24) | \
(_sett << 16))
/* /< store the status of scan mode low power and its setting */
#define IS_POWER_MODE(_mask, _mode) ((_mask&(_mode<<24)) != 0x00)
/* /< check the current mode of the IC */
/** @}*/
#define CMD_STR_LEN 32 /* /< max number of parameters that can accept
* the MP file node (stm_fts_cmd) */
#define TSP_BUF_SIZE PAGE_SIZE /* /< max number of bytes printable on
* the shell in the normal file nodes */
/**
* Struct which contains information about the HW platform and set up
*/
struct fts_hw_platform_data {
int (*power)(bool on);
int irq_gpio; /* /< number of the gpio associated to the interrupt pin
* */
int reset_gpio; /* /< number of the gpio associated to the reset pin */
const char *vdd_reg_name; /* /< name of the VDD regulator */
const char *avdd_reg_name; /* /< name of the AVDD regulator */
};
/*
* Forward declaration
*/
struct fts_ts_info;
extern char tag[8]; /* /< forward the definition of the label used
* to print the log in the kernel log */
/*
* Dispatch event handler
*/
typedef void (*event_dispatch_handler_t)
(struct fts_ts_info *info, unsigned char *data);
/**
* FTS capacitive touch screen device information
* - dev Pointer to the structure device \n
* - client client structure \n
* - input_dev Input device structure \n
* - work Work thread \n
* - event_wq Event queue for work thread \n
* - event_dispatch_table Event dispatch table handlers \n
* - attrs SysFS attributes \n
* - mode Device operating mode (bitmask) \n
* - touch_id Bitmask for touch id (mapped to input slots) \n
* - stylus_id Bitmask for tracking the stylus touches (mapped using the
* touchId) \n
* - timer Timer when operating in polling mode \n
* - power Power on/off routine \n
* - board HW info retrieved from device tree \n
* - vdd_reg DVDD power regulator \n
* - avdd_reg AVDD power regulator \n
* - resume_bit Indicate if screen off/on \n
* - fwupdate_stat Store the result of a fw update triggered by the host \n
* - notifier Used for be notified from a suspend/resume event \n
* - sensor_sleep true suspend was called, false resume was called \n
* - wakesrc Wakeup Source struct \n
* - input_report_mutex mutex for handling the pressure of keys \n
* - series_of_switches to store the enabling status of a particular feature
* from the host \n
*/
struct fts_ts_info {
struct device *dev; /* /< Pointer to the structure device */
#ifdef I2C_INTERFACE
struct i2c_client *client; /* /< I2C client structure */
#else
struct spi_device *client; /* /< SPI client structure */
#endif
struct input_dev *input_dev; /* /< Input device structure */
struct work_struct work; /* /< Event work thread */
struct work_struct suspend_work; /* /< Suspend work thread */
struct work_struct resume_work; /* /< Resume work thread */
struct workqueue_struct *event_wq; /* /< Workqueue used for event
* handler, suspend and resume
* work threads */
#ifndef FW_UPDATE_ON_PROBE
struct delayed_work fwu_work; /* /< Delayed work thread for fw update
* process */
struct workqueue_struct *fwu_workqueue; /* /< Fw update work
* queue */
#endif
event_dispatch_handler_t *event_dispatch_table; /* /< Event dispatch
* table handlers */
struct attribute_group attrs; /* /< SysFS attributes */
unsigned int mode; /* /< Device operating mode (bitmask: msb
* indicate if active or lpm) */
unsigned long touch_id; /* /< Bitmask for touch id (mapped to input
* slots) */
#ifdef STYLUS_MODE
unsigned long stylus_id; /* /< Bitmask for tracking the stylus
* touches (mapped using the touchId) */
#endif
struct fts_hw_platform_data *board; /* /< HW info retrieved from
* device tree */
struct regulator *vdd_reg; /* /< DVDD power regulator */
struct regulator *avdd_reg; /* /< AVDD power regulator */
int resume_bit; /* /< Indicate if screen off/on */
int fwupdate_stat; /* /< Store the result of a fw update triggered
* by the host */
struct notifier_block notifier; /* /< Used for be notified from a
* suspend/resume event */
bool sensor_sleep; /* /< if true suspend was called while if false
* resume was called */
struct wakeup_source wakesrc; /* Wake Lock struct */
/* input lock */
struct mutex input_report_mutex; /* /< mutex for handling the report
* of the pressure of keys */
/* switches for features */
int gesture_enabled; /* /< if set, the gesture mode will be enabled
* during the suspend */
int glove_enabled; /* /< if set, the glove mode will be enabled
* when allowed */
int charger_enabled; /* /< if set, the charger mode will be enabled
* when allowed */
int stylus_enabled; /* /< if set, the stylus mode will be enabled
* when allowed */
int cover_enabled; /* /< if set, the cover mode will be enabled
* when allowed */
int grip_enabled; /* /< if set, the grip mode mode will be enabled
* when allowed */
};
int fts_chip_powercycle(struct fts_ts_info *info);
extern int input_register_notifier_client(struct notifier_block *nb);
extern int input_unregister_notifier_client(struct notifier_block *nb);
/* export declaration of functions in fts_proc.c */
extern int fts_proc_init(void);
extern int fts_proc_remove(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
#
# Makefile for the FTS touchscreen driver.
#
obj-y += ftsCompensation.o ftsCore.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o

View file

@ -0,0 +1,822 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting Initialization Data *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsCompensation.c
* \brief Contains all the function to work with Initialization Data
*/
#include "ftsCompensation.h"
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsFrame.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsSoftware.h"
#include "ftsTime.h"
#include "ftsTool.h"
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/ctype.h>
/**
* Request to the FW to load the specified Initialization Data
* @param type type of Initialization data to load @link load_opt Load Host
* Data Option @endlink
* @return OK if success or an error code which specify the type of error
*/
int requestCompensationData(u8 type)
{
int ret = ERROR_OP_NOT_ALLOW;
int retry = 0;
logError(0, "%s %s: Requesting compensation data... attemp = %d\n", tag,
__func__, retry + 1);
while (retry < RETRY_COMP_DATA_READ) {
ret = writeSysCmd(SYS_CMD_LOAD_DATA, &type, 1);
/* send request to load in memory the Compensation Data */
if (ret < OK) {
logError(1, "%s %s: failed at %d attemp!\n", tag,
__func__, retry + 1);
retry += 1;
} else {
logError(0,
"%s %s: Request Compensation data FINISHED!\n",
tag,
__func__);
return OK;
}
}
logError(1, "%s %s: Requesting compensation data... ERROR %08X\n", tag,
__func__, ret | ERROR_REQU_COMP_DATA);
return ret | ERROR_REQU_COMP_DATA;
}
/**
* Read Initialization Data Header and check that the type loaded match
* with the one previously requested
* @param type type of Initialization data requested @link load_opt Load Host
* Data Option @endlink
* @param header pointer to DataHeader variable which will contain the header
* @param address pointer to a variable which will contain the updated address
* to the next data
* @return OK if success or an error code which specify the type of error
*/
int readCompensationDataHeader(u8 type, DataHeader *header, u64 *address)
{
u64 offset = ADDR_FRAMEBUFFER;
u8 data[COMP_DATA_HEADER];
int ret;
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, offset, data,
COMP_DATA_HEADER, DUMMY_FRAMEBUFFER);
if (ret < OK) { /* i2c function have already a retry mechanism */
logError(1,
"%s %s: error while reading data header ERROR %08X\n",
tag,
__func__, ret);
return ret;
}
logError(0, "%s Read Data Header done!\n", tag);
if (data[0] != HEADER_SIGNATURE) {
logError(1,
"%s %s: The Header Signature was wrong! %02X != %02X ERROR %08X\n",
tag, __func__, data[0], HEADER_SIGNATURE,
ERROR_WRONG_DATA_SIGN);
return ERROR_WRONG_DATA_SIGN;
}
if (data[1] != type) {
logError(1, "%s %s: Wrong type found! %02X!=%02X ERROR %08X\n",
tag, __func__, data[1], type, ERROR_DIFF_DATA_TYPE);
return ERROR_DIFF_DATA_TYPE;
}
logError(0, "%s Type = %02X of Compensation data OK!\n", tag, type);
header->type = type;
*address = offset + COMP_DATA_HEADER;
return OK;
}
/**
* Read MS Global Initialization data from the buffer such as Cx1
* @param address pointer to a variable which contain the address from where
* to read the data and will contain the updated address to the next data
* @param global pointer to MutualSenseData variable which will contain the MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readMutualSenseGlobalData(u64 *address, MutualSenseData *global)
{
u8 data[COMP_DATA_GLOBAL];
int ret;
logError(0, "%s Address for Global data= %08llX\n", tag, *address);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: error while reading info data ERROR %08X\n",
tag, __func__, ret);
return ret;
}
logError(0, "%s Global data Read !\n", tag);
global->header.force_node = data[0];
global->header.sense_node = data[1];
global->cx1 = data[2];
/* all other bytes are reserved atm */
logError(0, "%s force_len = %d sense_len = %d CX1 = %d\n", tag,
global->header.force_node, global->header.sense_node,
global->cx1);
*address += COMP_DATA_GLOBAL;
return OK;
}
/**
* Read MS Initialization data for each node from the buffer
* @param address a variable which contain the address from where to read the
* data
* @param node pointer to MutualSenseData variable which will contain the MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readMutualSenseNodeData(u64 address, MutualSenseData *node)
{
int ret;
int size = node->header.force_node * node->header.sense_node;
logError(0, "%s Address for Node data = %08llX\n", tag, address);
node->node_data = (i8 *)kmalloc(size * (sizeof(i8)), GFP_KERNEL);
if (node->node_data == NULL) {
logError(1, "%s %s: can not allocate node_data... ERROR %08X",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
logError(0, "%s Node Data to read %d bytes\n", tag, size);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address,
node->node_data, size, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1,
"%s %s: error while reading node data ERROR %08X\n",
tag,
__func__, ret);
kfree(node->node_data);
return ret;
}
node->node_data_size = size;
logError(0, "%s Read node data OK!\n", tag);
return size;
}
/**
* Perform all the steps to read the necessary info for MS Initialization data
* from the buffer and store it in a MutualSenseData variable
* @param type type of MS Initialization data to read @link load_opt Load Host
* Data Option @endlink
* @param data pointer to MutualSenseData variable which will contain the MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readMutualSenseCompensationData(u8 type, MutualSenseData *data)
{
int ret;
u64 address;
data->node_data = NULL;
if (!(type == LOAD_CX_MS_TOUCH || type == LOAD_CX_MS_LOW_POWER ||
type == LOAD_CX_MS_KEY || type == LOAD_CX_MS_FORCE)) {
logError(1,
"%s %s: Choose a MS type of compensation data ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\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 %08X\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 %08X\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 %08X\n", tag, __func__,
ERROR_COMP_DATA_NODE);
return ret | ERROR_COMP_DATA_NODE;
}
return OK;
}
/**
* Read SS Global Initialization data from the buffer such as Ix1/Cx1 for force
* and sense
* @param address pointer to a variable which contain the address from where
* to read the data and will contain the updated address to the next data
* @param global pointer to MutualSenseData variable which will contain the SS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readSelfSenseGlobalData(u64 *address, SelfSenseData *global)
{
int ret;
u8 data[COMP_DATA_GLOBAL];
logError(0, "%s Address for Global data= %08llX\n", tag, *address);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1,
"%s %s: error while reading the data... ERROR %08X\n",
tag,
__func__, ret);
return ret;
}
logError(0, "%s Global data Read !\n", tag);
global->header.force_node = data[0];
global->header.sense_node = data[1];
global->f_ix1 = data[2];
global->s_ix1 = data[3];
global->f_cx1 = (i8)data[4];
global->s_cx1 = (i8)data[5];
global->f_max_n = data[6];
global->s_max_n = data[7];
global->f_ix0 = data[8];
global->s_ix0 = data[9];
logError(0,
"%s force_len = %d sense_len = %d f_ix1 = %d s_ix1 = %d f_cx1 = %d s_cx1 = %d\n",
tag, global->header.force_node, global->header.sense_node,
global->f_ix1, global->s_ix1, global->f_cx1, global->s_cx1);
logError(0, "%s max_n = %d s_max_n = %d f_ix0 = %d s_ix0 = %d\n",
tag, global->f_max_n, global->s_max_n,
global->f_ix0, global->s_ix0);
*address += COMP_DATA_GLOBAL;
return OK;
}
/**
* Read SS Initialization data for each node of force and sense channels from
* the buffer
* @param address a variable which contain the address from where to read the
* data
* @param node pointer to SelfSenseData variable which will contain the SS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readSelfSenseNodeData(u64 address, SelfSenseData *node)
{
int size = node->header.force_node * 2 + node->header.sense_node * 2;
u8 data[size];
int ret;
node->ix2_fm = (u8 *)kmalloc(node->header.force_node * (sizeof(u8)),
GFP_KERNEL);
if (node->ix2_fm == NULL) {
logError(1,
"%s %s: can not allocate memory for ix2_fm... ERROR %08X",
tag,
__func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
node->cx2_fm = (i8 *)kmalloc(node->header.force_node * (sizeof(i8)),
GFP_KERNEL);
if (node->cx2_fm == NULL) {
logError(1,
"%s %s: can not allocate memory for cx2_fm ... ERROR %08X",
tag,
__func__, ERROR_ALLOC);
kfree(node->ix2_fm);
return ERROR_ALLOC;
}
node->ix2_sn = (u8 *)kmalloc(node->header.sense_node * (sizeof(u8)),
GFP_KERNEL);
if (node->ix2_sn == NULL) {
logError(1,
"%s %s: can not allocate memory for ix2_sn ERROR %08X",
tag,
__func__, ERROR_ALLOC);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
return ERROR_ALLOC;
}
node->cx2_sn = (i8 *)kmalloc(node->header.sense_node * (sizeof(i8)),
GFP_KERNEL);
if (node->cx2_sn == NULL) {
logError(1,
"%s %s: can not allocate memory for cx2_sn ERROR %08X",
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 = %08llX\n", tag, address);
logError(0, "%s Node Data to read %d bytes\n", tag, size);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data,
size, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: error while reading data... ERROR %08X\n",
tag, __func__, ret);
kfree(node->ix2_fm);
kfree(node->cx2_fm);
kfree(node->ix2_sn);
kfree(node->cx2_sn);
return ret;
}
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);
return OK;
}
/**
* Perform all the steps to read the necessary info for SS Initialization data
* from the buffer and store it in a SelfSenseData variable
* @param type type of SS Initialization data to read @link load_opt Load Host
* Data Option @endlink
* @param data pointer to SelfSenseData variable which will contain the SS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readSelfSenseCompensationData(u8 type, SelfSenseData *data)
{
int ret;
u64 address;
data->ix2_fm = NULL;
data->cx2_fm = NULL;
data->ix2_sn = NULL;
data->cx2_sn = NULL;
if (!(type == LOAD_CX_SS_TOUCH || type == LOAD_CX_SS_TOUCH_IDLE ||
type == LOAD_CX_SS_KEY || type == LOAD_CX_SS_FORCE)) {
logError(1,
"%s %s: Choose a SS type of compensation data ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1,
"%s %s: error while requesting data... ERROR %08X\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 while reading data header... ERROR %08X\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 %08X\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 %08X\n", tag, __func__,
ERROR_COMP_DATA_NODE);
return ret | ERROR_COMP_DATA_NODE;
}
return OK;
}
/**
* Read TOT MS Global Initialization data from the buffer such as number of
* force and sense channels
* @param address pointer to a variable which contain the address from where
* to read the data and will contain the updated address to the next data
* @param global pointer to a variable which will contain the TOT MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotMutualSenseGlobalData(u64 *address, TotMutualSenseData *global)
{
int ret;
u8 data[COMP_DATA_GLOBAL];
logError(0, "%s Address for Global data= %04llX\n", tag, *address);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: error while reading info data ERROR %08X\n",
tag, __func__, ret);
return ret;
}
logError(0, "%s Global data Read !\n", tag);
global->header.force_node = data[0];
global->header.sense_node = data[1];
/* all other bytes are reserved atm */
logError(0, "%s force_len = %d sense_len = %d\n", tag,
global->header.force_node, global->header.sense_node);
*address += COMP_DATA_GLOBAL;
return OK;
}
/**
* Read TOT MS Initialization data for each node from the buffer
* @param address a variable which contain the address from where to read the
* data
* @param node pointer to MutualSenseData variable which will contain the TOT
* MS initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotMutualSenseNodeData(u64 address, TotMutualSenseData *node)
{
int ret, i;
int size = node->header.force_node * node->header.sense_node;
int toRead = size * sizeof(u16);
u8 data[toRead];
logError(0, "%s Address for Node data = %04llX\n", tag, address);
node->node_data = (short *)kmalloc(size * (sizeof(short)), GFP_KERNEL);
if (node->node_data == NULL) {
logError(1, "%s %s: can not allocate node_data... ERROR %08X",
tag, __func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
logError(0, "%s Node Data to read %d bytes\n", tag, size);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data,
toRead, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1,
"%s %s: error while reading node data ERROR %08X\n",
tag,
__func__, ret);
kfree(node->node_data);
return ret;
}
node->node_data_size = size;
for (i = 0; i < size; i++)
node->node_data[i] = ((short)data[i * 2 + 1]) << 8 | data[i *
2];
logError(0, "%s Read node data OK!\n", tag);
return size;
}
/**
* Perform all the steps to read the necessary info for TOT MS Initialization
* data from the buffer and store it in a TotMutualSenseData variable
* @param type type of TOT MS Initialization data to read @link load_opt Load
* Host Data Option @endlink
* @param data pointer to a variable which will contain the TOT MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotMutualSenseCompensationData(u8 type, TotMutualSenseData *data)
{
int ret;
u64 address;
data->node_data = NULL;
if (!(type == LOAD_PANEL_CX_TOT_MS_TOUCH || type ==
LOAD_PANEL_CX_TOT_MS_LOW_POWER || type ==
LOAD_PANEL_CX_TOT_MS_KEY ||
type == LOAD_PANEL_CX_TOT_MS_FORCE)) {
logError(1,
"%s %s: Choose a TOT MS type of compensation data ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\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 %08X\n", tag, __func__,
ERROR_COMP_DATA_HEADER);
return ret | ERROR_COMP_DATA_HEADER;
}
ret = readTotMutualSenseGlobalData(&address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__,
ERROR_COMP_DATA_GLOBAL);
return ret | ERROR_COMP_DATA_GLOBAL;
}
ret = readTotMutualSenseNodeData(address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__,
ERROR_COMP_DATA_NODE);
return ret | ERROR_COMP_DATA_NODE;
}
return OK;
}
/**
* Read TOT SS Global Initialization data from the buffer such as number of
* force and sense channels
* @param address pointer to a variable which contain the address from where
* to read the data and will contain the updated address to the next data
* @param global pointer to a variable which will contain the TOT SS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotSelfSenseGlobalData(u64 *address, TotSelfSenseData *global)
{
int ret;
u8 data[COMP_DATA_GLOBAL];
logError(0, "%s Address for Global data= %04llX\n", tag, *address);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data,
COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1,
"%s %s: error while reading the data... ERROR %08X\n",
tag,
__func__, ret);
return ret;
}
logError(0, "%s Global data Read !\n", tag);
global->header.force_node = data[0];
global->header.sense_node = data[1];
logError(0, "%s force_len = %d sense_len = %d\n", tag,
global->header.force_node, global->header.sense_node);
*address += COMP_DATA_GLOBAL;
return OK;
}
/**
* Read TOT SS Global Initialization data from the buffer such as number of
* force and sense channels
* @param address pointer to a variable which contain the address from where
* to read the data and will contain the updated address to the next data
* @param node pointer to a variable which will contain the TOT SS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotSelfSenseNodeData(u64 address, TotSelfSenseData *node)
{
int size = node->header.force_node * 2 + node->header.sense_node * 2;
int toRead = size * 2; /* *2 2 bytes each node */
u8 data[toRead];
int ret, i, j = 0;
node->ix_fm = (u16 *)kmalloc(node->header.force_node * (sizeof(u16)),
GFP_KERNEL);
if (node->ix_fm == NULL) {
logError(1,
"%s %s: can not allocate memory for ix2_fm... ERROR %08X",
tag,
__func__, ERROR_ALLOC);
return ERROR_ALLOC;
}
node->cx_fm = (short *)kmalloc(node->header.force_node *
(sizeof(short)), GFP_KERNEL);
if (node->cx_fm == NULL) {
logError(1,
"%s %s: can not allocate memory for cx2_fm ... ERROR %08X",
tag,
__func__, ERROR_ALLOC);
kfree(node->ix_fm);
return ERROR_ALLOC;
}
node->ix_sn = (u16 *)kmalloc(node->header.sense_node * (sizeof(u16)),
GFP_KERNEL);
if (node->ix_sn == NULL) {
logError(1,
"%s %s: can not allocate memory for ix2_sn ERROR %08X",
tag,
__func__, ERROR_ALLOC);
kfree(node->ix_fm);
kfree(node->cx_fm);
return ERROR_ALLOC;
}
node->cx_sn = (short *)kmalloc(node->header.sense_node *
(sizeof(short)), GFP_KERNEL);
if (node->cx_sn == NULL) {
logError(1,
"%s %s: can not allocate memory for cx2_sn ERROR %08X",
tag,
__func__, ERROR_ALLOC);
kfree(node->ix_fm);
kfree(node->cx_fm);
kfree(node->ix_sn);
return ERROR_ALLOC;
}
logError(0, "%s Address for Node data = %04llX\n", tag, address);
logError(0, "%s Node Data to read %d bytes\n", tag, size);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data,
toRead, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: error while reading data... ERROR %08X\n",
tag, __func__, ret);
kfree(node->ix_fm);
kfree(node->cx_fm);
kfree(node->ix_sn);
kfree(node->cx_sn);
return ret;
}
logError(0, "%s Read node data ok!\n", tag);
j = 0;
for (i = 0; i < node->header.force_node; i++) {
node->ix_fm[i] = ((u16)data[j + 1]) << 8 | data[j];
j += 2;
}
for (i = 0; i < node->header.sense_node; i++) {
node->ix_sn[i] = ((u16)data[j + 1]) << 8 | data[j];
j += 2;
}
for (i = 0; i < node->header.force_node; i++) {
node->cx_fm[i] = ((short)data[j + 1]) << 8 | data[j];
j += 2;
}
for (i = 0; i < node->header.sense_node; i++) {
node->cx_sn[i] = ((short)data[j + 1]) << 8 | data[j];
j += 2;
}
if (j != toRead)
logError(1, "%s %s: parsed a wrong number of bytes %d!=%d\n",
tag, __func__, j, toRead);
return OK;
}
/**
* Perform all the steps to read the necessary info for TOT SS Initialization
* data from the buffer and store it in a TotSelfSenseData variable
* @param type type of TOT MS Initialization data to read @link load_opt Load
* Host Data Option @endlink
* @param data pointer to a variable which will contain the TOT MS
* initialization data
* @return OK if success or an error code which specify the type of error
*/
int readTotSelfSenseCompensationData(u8 type, TotSelfSenseData *data)
{
int ret;
u64 address;
data->ix_fm = NULL;
data->cx_fm = NULL;
data->ix_sn = NULL;
data->cx_sn = NULL;
if (!(type == LOAD_PANEL_CX_TOT_SS_TOUCH || type ==
LOAD_PANEL_CX_TOT_SS_TOUCH_IDLE || type ==
LOAD_PANEL_CX_TOT_SS_KEY ||
type == LOAD_PANEL_CX_TOT_SS_FORCE)) {
logError(1,
"%s %s: Choose a TOT SS type of compensation data ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
ret = requestCompensationData(type);
if (ret < 0) {
logError(1,
"%s %s: error while requesting data... ERROR %08X\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 while reading data header... ERROR %08X\n",
tag,
__func__, ERROR_COMP_DATA_HEADER);
return ret | ERROR_COMP_DATA_HEADER;
}
ret = readTotSelfSenseGlobalData(&address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__,
ERROR_COMP_DATA_GLOBAL);
return ret | ERROR_COMP_DATA_GLOBAL;
}
ret = readTotSelfSenseNodeData(address, data);
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__,
ERROR_COMP_DATA_NODE);
return ret | ERROR_COMP_DATA_NODE;
}
return OK;
}

View file

@ -0,0 +1,136 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting Initialization Data **
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsCompensation.h
* \brief Contains all the definitions and structs to work with Initialization
* Data
*/
#ifndef FTS_COMPENSATION_H
#define FTS_COMPENSATION_H
#include "ftsCore.h"
#include "ftsSoftware.h"
#define RETRY_COMP_DATA_READ 2 /* /< max number of attempts to read
* initialization data */
/* Bytes dimension of Compensation Data Format */
#define COMP_DATA_HEADER DATA_HEADER /* /< size in bytes of
* initialization data header */
#define COMP_DATA_GLOBAL (16 - COMP_DATA_HEADER) /* /< size in bytes
* of initialization
*data general info */
#define HEADER_SIGNATURE 0xA5 /* /< signature used as starting byte of
* data loaded in memory */
/**
* Struct which contains the general info about Frames and Initialization Data
*/
typedef struct {
int force_node; /* /< Number of Force Channels in the
* frame/Initialization data */
int sense_node; /* /< Number of Sense Channels in the
* frame/Initialization data */
int type; /* /< Type of frame/Initialization data */
} DataHeader;
/**
* Struct which contains the MS Initialization data
*/
typedef struct {
DataHeader header; /* /< Header */
i8 cx1; /* /< Cx1 value (can be negative)) */
i8 *node_data; /* /< Pointer to an array of bytes which contains the
* CX2 data (can be negative) */
int node_data_size; /* /< size of the data */
} MutualSenseData;
/**
* Struct which contains the SS Initialization data
*/
typedef struct {
DataHeader header; /* /< Header */
u8 f_ix1; /* /< IX1 Force */
u8 s_ix1; /* /< IX1 Sense */
i8 f_cx1; /* /< CX1 Force (can be negative) */
i8 s_cx1; /* /< CX1 Sense (can be negative) */
u8 f_max_n; /* /< Force MaxN */
u8 s_max_n; /* /< Sense MaxN */
u8 f_ix0; /* /< IX0 Force */
u8 s_ix0; /* /< IX0 Sense */
u8 *ix2_fm; /* /< pointer to an array of bytes which contains Force
* Ix2 data node */
u8 *ix2_sn; /* /< pointer to an array of bytes which contains Sense
* Ix2 data node */
i8 *cx2_fm; /* /< pointer to an array of bytes which contains Force
* Cx2 data node (can be negative) */
i8 *cx2_sn; /* /< pointer to an array of bytes which contains Sense
* Cx2 data node (can be negative)) */
} SelfSenseData;
/**
* Struct which contains the TOT MS Initialization data
*/
typedef struct {
DataHeader header; /* /< Header */
short *node_data; /* /< pointer to an array of ushort which
* contains TOT MS Initialization data */
int node_data_size; /* /< size of data */
} TotMutualSenseData;
/**
* Struct which contains the TOT SS Initialization data
*/
typedef struct {
DataHeader header; /* /< Header */
u16 *ix_fm; /* /< pointer to an array of ushort which contains TOT
* SS IX Force data */
u16 *ix_sn; /* /< pointer to an array of ushort which contains TOT
* SS IX Sense data */
short *cx_fm; /* /< pointer to an array of ushort which contains TOT
* SS CX Force data (can be negative) */
short *cx_sn; /* /< pointer to an array of ushort which contains TOT
* SS CX Sense data (can be negative) */
} TotSelfSenseData;
int requestCompensationData(u8 type);
int readCompensationDataHeader(u8 type, DataHeader *header, u64 *address);
int readMutualSenseGlobalData(u64 *address, MutualSenseData *global);
int readMutualSenseNodeData(u64 address, MutualSenseData *node);
int readMutualSenseCompensationData(u8 type, MutualSenseData *data);
int readSelfSenseGlobalData(u64 *address, SelfSenseData *global);
int readSelfSenseNodeData(u64 address, SelfSenseData *node);
int readSelfSenseCompensationData(u8 type, SelfSenseData *data);
int readToTMutualSenseGlobalData(u64 *address, TotMutualSenseData *global);
int readToTMutualSenseNodeData(u64 address, TotMutualSenseData *node);
int readTotMutualSenseCompensationData(u8 type, TotMutualSenseData *data);
int readTotSelfSenseGlobalData(u64 *address, TotSelfSenseData *global);
int readTotSelfSenseNodeData(u64 address, TotSelfSenseData *node);
int readTotSelfSenseCompensationData(u8 type, TotSelfSenseData *data);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,219 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Core definitions **
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsCore.h
* \brief Contains all the definitions and structs of Core functionalities
*/
#ifndef FTS_CORE_H
#define FTS_CORE_H
#include "ftsHardware.h"
#include "ftsSoftware.h"
#include "../fts.h"
/* HW DATA */
#define GPIO_NOT_DEFINED -1 /* /< value assumed by reset_gpio when
* the reset pin of the IC is not
* connected */
#define ADDR_SIZE_HW_REG BITS_32 /* /< value of AddrSize for Hw register
* in FTI @see AddrSize */
#define DATA_HEADER 4 /* /< size in byte of the header loaded
* with the data in the frambuffer */
/**
* Type of CRC errors
*/
typedef enum {
CRC_CODE = 1, /* /< CRC in the code section */
CRC_CONFIG = 2, /* /< CRC in the config section */
CRC_CX = 3, /* /< CRC in the cx section */
CRC_PANEL = 4 /* /< CRC in the panel section */
} CRC_Error;
/* CHIP INFO */
/** @defgroup system_info System Info
* System Info Data collect the most important informations about hw and fw
* @{
*/
/* Size in bytes of System Info data */
#define SYS_INFO_SIZE 216 /* Num bytes of die info */
#define DIE_INFO_SIZE 16 /* Num bytes of external release
* in config */
#define EXTERNAL_RELEASE_INFO_SIZE 8 /* Num bytes of release info in
* sys info
* (first bytes are external
*release) */
#define RELEASE_INFO_SIZE (EXTERNAL_RELEASE_INFO_SIZE)
/** @}*/
/* RETRY MECHANISM */
#define RETRY_MAX_REQU_DATA 2 /* /< Max number of attemps
* performed
* when requesting data */
#define RETRY_SYSTEM_RESET 3 /* /< Max number of attemps
* performed
* to reset the IC */
/** @addtogroup system_info
* @{
*/
/**
* Struct which contains fundamental informations about the chip and its
*configuration
*/
typedef struct {
u16 u16_apiVer_rev; /* /< API revision version */
u8 u8_apiVer_minor; /* /< API minor version */
u8 u8_apiVer_major; /* /< API major version */
u16 u16_chip0Ver; /* /< Dev0 version */
u16 u16_chip0Id; /* /< Dev0 ID */
u16 u16_chip1Ver; /* /< Dev1 version */
u16 u16_chip1Id; /* /< Dev1 ID */
u16 u16_fwVer; /* /< Fw version */
u16 u16_svnRev; /* /< SVN Revision */
u16 u16_cfgVer; /* /< Config Version */
u16 u16_cfgProjectId; /* /< Config Project ID */
u16 u16_cxVer; /* /< Cx Version */
u16 u16_cxProjectId; /* /< Cx Project ID */
u8 u8_cfgAfeVer; /* /< AFE version in Config */
u8 u8_cxAfeVer; /* /< AFE version in CX */
u8 u8_panelCfgAfeVer; /* /< AFE version in PanelMem */
u8 u8_protocol; /* /< Touch Report Protocol */
u8 u8_dieInfo[DIE_INFO_SIZE]; /* /< Die information */
u8 u8_releaseInfo[RELEASE_INFO_SIZE]; /* /< Release information */
u32 u32_fwCrc; /* /< Crc of FW */
u32 u32_cfgCrc; /* /< Crc of config */
u8 u8_mpFlag; /* /< MP Flag */
u8 u8_ssDetScanSet; /* /< Type of Detect Scan Selected */
u16 u16_scrResX; /* /< X resolution on main screen */
u16 u16_scrResY; /* /< Y resolution on main screen */
u8 u8_scrTxLen; /* /< Tx length */
u8 u8_scrRxLen; /* /< Rx length */
u8 u8_keyLen; /* /< Key Len */
u8 u8_forceLen; /* /< Force Len */
u32 u32_productionTimestamp; /* /< Production Timestamp */
u16 u16_dbgInfoAddr; /* /< Offset of debug Info structure */
u16 u16_msTchRawAddr; /* /< Offset of MS touch raw frame */
u16 u16_msTchFilterAddr; /* /< Offset of MS touch filter frame */
u16 u16_msTchStrenAddr; /* /< Offset of MS touch strength frame */
u16 u16_msTchBaselineAddr; /* /< Offset of MS touch baseline frame
* */
u16 u16_ssTchTxRawAddr; /* /< Offset of SS touch force raw frame */
u16 u16_ssTchTxFilterAddr; /* /< Offset of SS touch force filter
* frame */
u16 u16_ssTchTxStrenAddr; /* /< Offset of SS touch force strength
* frame */
u16 u16_ssTchTxBaselineAddr; /* /< Offset of SS touch force baseline
* frame */
u16 u16_ssTchRxRawAddr; /* /< Offset of SS touch sense raw frame */
u16 u16_ssTchRxFilterAddr; /* /< Offset of SS touch sense filter
* frame */
u16 u16_ssTchRxStrenAddr; /* /< Offset of SS touch sense strength
* frame */
u16 u16_ssTchRxBaselineAddr; /* /< Offset of SS touch sense baseline
* frame */
u16 u16_keyRawAddr; /* /< Offset of key raw frame */
u16 u16_keyFilterAddr; /* /< Offset of key filter frame */
u16 u16_keyStrenAddr; /* /< Offset of key strength frame */
u16 u16_keyBaselineAddr; /* /< Offset of key baseline frame */
u16 u16_frcRawAddr; /* /< Offset of force touch raw frame */
u16 u16_frcFilterAddr; /* /< Offset of force touch filter frame */
u16 u16_frcStrenAddr; /* /< Offset of force touch strength frame */
u16 u16_frcBaselineAddr; /* /< Offset of force touch baseline
* frame */
u16 u16_ssHvrTxRawAddr; /* /< Offset of SS hover Force raw frame */
u16 u16_ssHvrTxFilterAddr; /* /< Offset of SS hover Force filter
* frame */
u16 u16_ssHvrTxStrenAddr; /* /< Offset of SS hover Force strength
* frame */
u16 u16_ssHvrTxBaselineAddr; /* /< Offset of SS hover Force baseline
* frame */
u16 u16_ssHvrRxRawAddr; /* /< Offset of SS hover Sense raw frame */
u16 u16_ssHvrRxFilterAddr; /* /< Offset of SS hover Sense filter
* frame */
u16 u16_ssHvrRxStrenAddr; /* /< Offset of SS hover Sense strength
* frame */
u16 u16_ssHvrRxBaselineAddr; /* /< Offset of SS hover Sense baseline
* frame */
u16 u16_ssPrxTxRawAddr; /* /< Offset of SS proximity force raw frame */
u16 u16_ssPrxTxFilterAddr; /* /< Offset of SS proximity force
* filter frame */
u16 u16_ssPrxTxStrenAddr; /* /< Offset of SS proximity force
* strength frame */
u16 u16_ssPrxTxBaselineAddr; /* /< Offset of SS proximity force
* baseline frame */
u16 u16_ssPrxRxRawAddr; /* /< Offset of SS proximity sense raw frame */
u16 u16_ssPrxRxFilterAddr; /* /< Offset of SS proximity sense
* filter frame */
u16 u16_ssPrxRxStrenAddr; /* /< Offset of SS proximity sense
* strength frame */
u16 u16_ssPrxRxBaselineAddr; /* /< Offset of SS proximity sense
* baseline frame */
u16 u16_ssDetRawAddr; /* /< Offset of SS detect raw frame */
u16 u16_ssDetFilterAddr; /* /< Offset of SS detect filter
* frame */
u16 u16_ssDetStrenAddr; /* /< Offset of SS detect strength
* frame */
u16 u16_ssDetBaselineAddr; /* /< Offset of SS detect baseline
* frame */
} SysInfo;
/** @}*/
int initCore(struct fts_ts_info *info);
void setResetGpio(int gpio);
int fts_system_reset(void);
int isSystemResettedUp(void);
int isSystemResettedDown(void);
void setSystemResetedUp(int val);
void setSystemResetedDown(int val);
int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int
time_to_wait);
int checkEcho(u8 *cmd, int size);
int setScanMode(u8 mode, u8 settings);
int setFeatures(u8 feat, u8 *settings, int size);
int defaultSysInfo(int i2cError);
int writeSysCmd(u8 sys_cmd, u8 *sett, int size);
int readSysInfo(int request);
int readConfig(u16 offset, u8 *outBuf, int len);
int writeConfig(u16 offset, u8 *data, int len);
int fts_disableInterrupt(void);
int fts_disableInterruptNoSync(void);
int fts_resetDisableIrqCount(void);
int fts_enableInterrupt(void);
int fts_crc_check(void);
int requestSyncFrame(u8 type);
int saveMpFlag(u8 mpflag);
#endif /* FTS_CORE_H */

View file

@ -0,0 +1,371 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS error/info kernel log reporting *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsError.c
* \brief Contains all the function which handle with Error conditions
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "../fts.h"
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsIO.h"
#include "ftsTool.h"
#include "ftsCompensation.h"
static ErrorList errors; /* /< private variable which implement the Error
* List */
/**
* Print messages in the kernel log
* @param force if 1, the log is printed always otherwise only if DEBUG is
* defined, the log will be printed
* @param msg string containing the message to print
* @param ... additional parameters that are used in msg according the format
* of printf
*/
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);
}
}
/**
* Check if an error code is related to an I2C failure
* @param error error code to check
* @return 1 if the first level error code is I2C related otherwise 0
*/
int isI2cError(int error)
{
if (((error & 0x000000FF) >= (ERROR_BUS_R & 0x000000FF)) &&
((error & 0x000000FF) <= (ERROR_BUS_O & 0x000000FF)))
return 1;
else
return 0;
}
/**
* Dump in the kernel log some debug info in case of FW hang
* @param outBuf (optional)pointer to bytes array where to copy the debug info,
* if NULL the data will just printed on the kernel log
* @param size dimension in bytes of outBuf,
* if > ERROR_DUMP_ROW_SIZE*ERROR_DUMP_COL_SIZE, only the first
* ERROR_DUMP_ROW_SIZE*ERROR_DUMP_COL_SIZE bytes will be copied
* @return OK if success or an error code which specify the type of error
*/
int dumpErrorInfo(u8 *outBuf, int size)
{
int ret, i;
u8 data[ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE] = { 0 };
u32 sign = 0;
logError(0, "%s %s: Starting dump of error info...\n", tag, __func__);
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, ADDR_ERROR_DUMP,
data, ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE,
DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s %s: reading data ERROR %08X\n", tag, __func__,
ret);
return ret;
} else {
if (outBuf != NULL) {
sign = size > ERROR_DUMP_ROW_SIZE *
ERROR_DUMP_COL_SIZE ? ERROR_DUMP_ROW_SIZE *
ERROR_DUMP_COL_SIZE : size;
memcpy(outBuf, data, sign);
logError(0, "%s %s: error info copied in the buffer!\n",
tag, __func__);
}
logError(1, "%s %s: Error Info =\n", tag, __func__);
u8ToU32(data, &sign);
if (sign != ERROR_DUMP_SIGNATURE)
logError(1,
"%s %s: Wrong Error 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_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE;
i++) {
if (i % ERROR_DUMP_COL_SIZE == 0)
logError(1, KERN_ERR "\n%s %s: %d) ", tag,
__func__, i / ERROR_DUMP_COL_SIZE);
logError(1, "%02X ", data[i]);
}
logError(1, "\n");
logError(0, "%s %s: dump of error info FINISHED!\n", tag,
__func__);
return OK;
}
}
/**
* Implement recovery strategies to be used when an error event is found
* while polling the FIFO
* @param event error event found during the polling
* @param size size of event
* @return OK if the error event doesn't require any action or the recovery
* strategy doesn't have any impact in the possible procedure that trigger the
* error, otherwise return an error code which specify the kind of error
* encountered. If ERROR_HANDLER_STOP_PROC the calling function must stop!
*/
int errorHandler(u8 *event, int size)
{
int res = OK;
struct fts_ts_info *info = NULL;
if (getDev() != NULL)
info = dev_get_drvdata(getDev());
if (info != NULL && event != NULL && size > 1 && event[0] ==
EVT_ID_ERROR) {
logError(1, "%s errorHandler: Starting handling...\n", tag);
addErrorIntoList(event, size);
switch (event[1]) { /* TODO: write an error log for
* undefined command subtype 0xBA */
case EVT_TYPE_ERROR_ESD: /* esd */
res = fts_chip_powercycle(info);
if (res < OK)
logError(1,
"%s errorHandler: Error performing powercycle ERROR %08X\n",
tag, res);
res = fts_system_reset();
if (res < OK)
logError(1,
"%s errorHandler: Cannot reset the device ERROR %08X\n",
tag, res);
res = (ERROR_HANDLER_STOP_PROC | res);
break;
case EVT_TYPE_ERROR_WATCHDOG: /* watchdog */
dumpErrorInfo(NULL, 0);
res = fts_system_reset();
if (res < OK)
logError(1,
"%s errorHandler: Cannot reset the device ERROR %08X\n",
tag, res);
res = (ERROR_HANDLER_STOP_PROC | res);
break;
case EVT_TYPE_ERROR_ITO_FORCETOGND:
logError(1, "%s errorHandler: Force Short to GND!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_SENSETOGND:
logError(1, "%s errorHandler: Sense short to GND!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_FORCETOVDD:
logError(1, "%s errorHandler: Force short to VDD!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_SENSETOVDD:
logError(1, "%s errorHandler: Sense short to VDD!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_FORCE_P2P:
logError(1,
"%s errorHandler: Force Pin to Pin Short!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_SENSE_P2P:
logError(1,
"%s errorHandler: Sense Pin to Pin Short!\n",
tag);
break;
case EVT_TYPE_ERROR_ITO_FORCEOPEN:
logError(1, "%s errorHandler: Force Open !\n", tag);
break;
case EVT_TYPE_ERROR_ITO_SENSEOPEN:
logError(1, "%s errorHandler: Sense Open !\n", tag);
break;
case EVT_TYPE_ERROR_ITO_KEYOPEN:
logError(1, "%s errorHandler: Key Open !\n", tag);
break;
default:
logError(1, "%s errorHandler: No Action taken!\n", tag);
break;
}
logError(1, "%s errorHandler: handling Finished! res = %08X\n",
tag, res);
return res;
} else {
logError(1,
"%s errorHandler: event Null or not correct size! ERROR %08X\n",
tag, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}
/**
* Add an error event into the Error List
* @param event error event to add
* @param size size of event
* @return OK
*/
int addErrorIntoList(u8 *event, int size)
{
int i = 0;
logError(0, "%s Adding error in to ErrorList...\n", tag);
memcpy(&errors.list[errors.last_index * FIFO_EVENT_SIZE], event, size);
i = FIFO_EVENT_SIZE - size;
if (i > 0) {
logError(0,
"%s Filling last %d bytes of the event with zero...\n",
tag, i);
memset(&errors.list[errors.last_index * FIFO_EVENT_SIZE + size],
0, i);
}
logError(0, "%s Adding error in to ErrorList... FINISHED!\n", tag);
errors.count += 1;
if (errors.count > FIFO_DEPTH)
logError(1,
"%s ErrorList is going in overflow... the first %d event(s) were override!\n",
tag, errors.count - FIFO_DEPTH);
errors.last_index = (errors.last_index + 1) % FIFO_DEPTH;
return OK;
}
/**
* Reset the Error List setting the count and last_index to 0.
* @return OK
*/
int resetErrorList(void)
{
errors.count = 0;
errors.last_index = 0;
memset(errors.list, 0, FIFO_DEPTH * FIFO_EVENT_SIZE);
/* if count is not considered is better reset also the list in order to
* avoid to read data previously copied into the list */
return OK;
}
/**
* Get the number of error events copied into the Error List
* @return the number of error events into the Error List
*/
int getErrorListCount(void)
{
if (errors.count > FIFO_DEPTH)
return FIFO_DEPTH;
else
return errors.count;
}
/* in case of success return the index of the event found */
/**
* Scroll the Error List looking for the event specified
* @param event_to_search event_to_search pointer to an array of int where
* each element correspond to a byte of the event to find. If the element
* of the array has value -1, the byte of the event, in the same position
* of the element is ignored.
* @param event_bytes size of event_to_search
* @return a value >=0 if the event is found which represent the index of
* the Error List where the event is located otherwise an error code
*/
int pollErrorList(int *event_to_search, int event_bytes)
{
int i = 0, j = 0, find = 0;
int count = getErrorListCount();
logError(1, "%s Starting to poll ErrorList...\n", tag);
while (find != 1 && i < count) {
find = 1;
for (j = 0; j < event_bytes; j++) {
if ((event_to_search[i] != -1) &&
((int)errors.list[i * FIFO_EVENT_SIZE + j] !=
event_to_search[i])) {
find = 0;
break;
}
}
i++;
}
if (find == 1) {
logError(1, "%s Error Found into ErrorList!\n", tag);
return i - 1; /* there is i++ at the end of the while */
} else {
logError(1, "%s Error Not Found into ErrorList! ERROR %08X\n",
tag, ERROR_TIMEOUT);
return ERROR_TIMEOUT;
}
}
/**
* Poll the Error List looking for any error types passed in the arguments.
* Return at the first match!
* @param list pointer to a list of error types to look for
* @param size size of list
* @return error type found if success or ERROR_TIMEOUT
*/
int pollForErrorType(u8 *list, int size)
{
int i = 0, j = 0, find = 0;
int count = getErrorListCount();
logError(1, "%s %s: Starting to poll ErrorList... count = %d\n", tag,
__func__, count);
while (find != 1 && i < count) {
for (j = 0; j < size; j++) {
if (list[j] == errors.list[i * FIFO_EVENT_SIZE + 1]) {
find = 1;
break;
}
}
i++;
}
if (find == 1) {
logError(1, "%s %s: Error Type %02X into ErrorList!\n", tag,
__func__, list[j]);
return list[j];
} else {
logError(1,
"%s %s: Error Type Not Found into ErrorList! ERROR %08X\n",
tag, __func__, ERROR_TIMEOUT);
return ERROR_TIMEOUT;
}
}

View file

@ -0,0 +1,236 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS error/info kernel log reporting *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsError.h
* \brief Contains all the definitions and structs which refer to Error
* conditions
*/
#ifndef FTS_ERROR_H
#define FTS_ERROR_H
#include "ftsHardware.h"
#include "ftsSoftware.h"
/** @defgroup error_codes Error Codes
* Error codes that can be reported by the driver functions.
* An error code is made up by 4 bytes, each byte indicate a logic error
* level.\n
* From the LSB to the MSB, the logic level increase going from a low level
* error (I2C,TIMEOUT) to an high level error (flashing procedure fail,
* production test fail etc)
* @{
*/
/* FIRST LEVEL ERROR CODE */
/** @defgroup first_level First Level Error Code
* @ingroup error_codes
* Errors related to low level operation which are not under control of driver,
* such as: communication protocol (I2C/SPI), timeout, file operations ...
* @{
*/
#define OK ((int)0x00000000) /* /< No ERROR */
#define ERROR_ALLOC ((int)0x80000001) /* /< allocation of
* memory failed */
#define ERROR_BUS_R ((int)0x80000002) /* /< i2c/spi read
* failed */
#define ERROR_BUS_W ((int)0x80000003) /* /< i2c/spi write
* failed */
#define ERROR_BUS_WR ((int)0x80000004) /* /< i2c/spi write/read
* failed */
#define ERROR_BUS_O ((int)0x80000005) /* /< error during
* opening an i2c device
*/
#define ERROR_OP_NOT_ALLOW ((int)0x80000006) /* /< operation not
* allowed */
#define ERROR_TIMEOUT ((int)0x80000007) /* /< timeout expired!
* exceed the max number
* of retries or the max
* waiting time */
#define ERROR_FILE_NOT_FOUND ((int)0x80000008) /* /< the file that i
* want to open is not
* found */
#define ERROR_FILE_PARSE ((int)0x80000009) /* /< error during
* parsing the file */
#define ERROR_FILE_READ ((int)0x8000000A) /* /< error during
* reading the file */
#define ERROR_LABEL_NOT_FOUND ((int)0x8000000B) /* /< label not found */
#define ERROR_FW_NO_UPDATE ((int)0x8000000C) /* /< fw in the chip
* newer than the one in
* the memmh */
#define ERROR_FLASH_UNKNOWN ((int)0x8000000D) /* /< flash status busy
* or unknown */
/** @}*/
/* SECOND LEVEL ERROR CODE */
/** @defgroup second_level Second Level Error Code
* @ingroup error_codes
* Errors related to simple logic operations in the IC which require one
* command or which are part of a more complex procedure
* @{
*/
#define ERROR_DISABLE_INTER ((int)0x80000200) /* /< unable to disable
* the interrupt */
#define ERROR_ENABLE_INTER ((int)0x80000300) /* /< unable to activate
* the interrup */
#define ERROR_READ_CONFIG ((int)0x80000400) /* /< failed to read
* config memory */
#define ERROR_GET_OFFSET ((int)0x80000500) /* /< unable to read an
* offset from memory */
#define ERROR_GET_FRAME_DATA ((int)0x80000600) /* /< unable to
* retrieve the data of
* a required frame */
#define ERROR_DIFF_DATA_TYPE ((int)0x80000700) /* /< FW answers with
* an event that has a
* different address
* respect the request
* done */
#define ERROR_WRONG_DATA_SIGN ((int)0x80000800) /* /< the signature of
* the host data is not
* HEADER_SIGNATURE */
#define ERROR_SET_SCAN_MODE_FAIL ((int)0x80000900) /* /< setting the
* scanning mode failed
* (sense on/off etc...)
*/
#define ERROR_SET_FEATURE_FAIL ((int)0x80000A00) /* /< setting a
* specific feature
* failed */
#define ERROR_SYSTEM_RESET_FAIL ((int)0x80000B00) /* /< the comand
* SYSTEM RESET
* failed */
#define ERROR_FLASH_NOT_READY ((int)0x80000C00) /* /< flash
* status not
* ready within
* a timeout */
#define ERROR_FW_VER_READ ((int)0x80000D00) /* /< unable to read
* fw_vers or the
* config_id */
#define ERROR_GESTURE_ENABLE_FAIL ((int)0x80000E00) /* /< unable to
* enable/disable the
* gesture */
#define ERROR_GESTURE_START_ADD ((int)0x80000F00) /* /< unable to start
* add custom gesture */
#define ERROR_GESTURE_FINISH_ADD ((int)0x80001000) /* /< unable to finish
* to add custom gesture
*/
#define ERROR_GESTURE_DATA_ADD ((int)0x80001100) /* /< unable to add
* custom gesture data
* */
#define ERROR_GESTURE_REMOVE ((int)0x80001200) /* /< unable to remove
* custom gesture data
*/
#define ERROR_FEATURE_ENABLE_DISABLE ((int)0x80001300) /* /< unable to
* enable/disable a
* feature mode in the
* IC */
#define ERROR_NOISE_PARAMETERS ((int)0x80001400) /* /< unable to
* set/read noise
* parameter in
* the IC */
#define ERROR_CH_LEN ((int)0x80001500) /* /< unable to read
* the force and/or
* sense length */
/** @}*/
/* THIRD LEVEL ERROR CODE */
/** @defgroup third_level Third Level Error Code
* @ingroup error_codes
* Errors related to logic operations in the IC which require more
*commands/steps or which are part of a more complex procedure
* @{
*/
#define ERROR_REQU_COMP_DATA ((int)0x80010000) /* /< compensation data
* request failed */
#define ERROR_REQU_DATA ((int)0x80020000) /* /< data request failed */
#define ERROR_COMP_DATA_HEADER ((int)0x80030000) /* /< unable to retrieve
* compensation data header */
#define ERROR_COMP_DATA_GLOBAL ((int)0x80040000) /* /< unable to retrieve the
* global compensation data */
#define ERROR_COMP_DATA_NODE ((int)0x80050000) /* /< unable to retrieve
* the compensation data
* for each node */
#define ERROR_TEST_CHECK_FAIL ((int)0x80060000) /* /< check of
* production limits or
* of fw answers failed */
#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 */
#define ERROR_LP_TIMER_TUNING ((int)0x800B0000) /* /< lp timer calibration
* failed */
#define ERROR_SAVE_CX_TUNING ((int)0x800C0000) /* /< save cx data to flash
* failed */
#define ERROR_HANDLER_STOP_PROC ((int)0x800D0000) /* /< stop the poll of
* the FIFO if
* particular errors are
* found */
#define ERROR_CHECK_ECHO_FAIL ((int)0x800E0000) /* /< unable to retrieve
* echo event */
#define ERROR_GET_FRAME ((int)0x800F0000) /* /< unable to get frame */
/** @}*/
/* FOURTH LEVEL ERROR CODE */
/** @defgroup fourth_level Fourth Level Error Code
* @ingroup error_codes
* Errors related to the highest logic operations in the IC which have an
* important impact on the driver flow or which require several commands and
* steps to be executed
* @{
*/
#define ERROR_PROD_TEST_DATA ((int)0x81000000) /* /< production
* data test failed */
#define ERROR_FLASH_PROCEDURE ((int)0x82000000) /* /< fw update
* procedure failed */
#define ERROR_PROD_TEST_ITO ((int)0x83000000) /* /< production
* ito test failed */
#define ERROR_PROD_TEST_INITIALIZATION ((int)0x84000000) /* /< production
* initialization test
* failed */
#define ERROR_GET_INIT_STATUS ((int)0x85000000) /* /< mismatch of MS
* or SS tuning_version
* */
/** @}*/
/** @}*/ /* end of error_commands section */
/**
* Struct which store an ordered list of the errors events encountered during
*the polling of a FIFO.
* The max number of error events that can be stored is equal to FIFO_DEPTH
*/
typedef struct {
u8 list[FIFO_DEPTH * FIFO_EVENT_SIZE]; /* /< byte array which contains
* the series of error events
* encountered from the last
* reset of the list. */
int count; /* /< number of error events stored in the list */
int last_index; /* /< index of the list where will be stored the next
* error event. Subtract -1 to have the index of the
* last error event! */
} ErrorList;
/* #define logError(_l, _msg, ...) pr_err(_msg, ##__VA_ARGS__) */
void logError(int force, const char *msg, ...);
int isI2cError(int error);
int dumpErrorInfo(u8 *outBuf, int size);
int errorHandler(u8 *event, int size);
int addErrorIntoList(u8 *event, int size);
int getErrorListCount(void);
int resetErrorList(void);
int pollErrorList(int *event_to_search, int event_bytes);
int pollForErrorType(u8 *list, int size);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS API for Flashing the IC *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsFlash.h
* \brief Contains all the definitions and structs to handle the FW update
*process
*/
#ifndef FTS_FLASH_H
#define FTS_FLASH_H
#include "ftsSoftware.h"
/* Flash possible status */
#define FLASH_READY 0 /* /< value to indicate that the flash
* is ready */
#define FLASH_BUSY 1 /* /< value to indicate that the flash
* is busy */
#define FLASH_UNKNOWN -1 /* /< value to indicate an unknown
* status of the flash */
#define FLASH_STATUS_BYTES 1 /* /< number of bytes to check for read
* the flash status */
/* Flash timing parameters */
#define FLASH_RETRY_COUNT 200 /* /< number of attemps to read the
* flash status */
#define FLASH_WAIT_BEFORE_RETRY 50 /* /< time to wait in ms between status
* readings */
#ifdef FW_H_FILE
#define PATH_FILE_FW "NULL"
#else
#define PATH_FILE_FW "st_fts.ftb" /* /< new FW bin file name */
#endif
#ifdef ALIX
#define FLASH_CHUNK (32 * 1024) /* /< Max number of bytes that
* the
* DMA can burn on the flash in
*one shot in FTI */
#else
#define FLASH_CHUNK (64 * 1024) /* /< Max number of bytes that
* the
* DMA can burn on the flash in
*one shot in FTI */
#endif
#define DMA_CHUNK 32 /* /< Max number of bytes that can be
* written in I2C to the DMA */
#define FLASH_ORG_INFO_INDEX 280
#define FLASH_PAGE_SIZE (4 * 1024) //page size of 4KB
/**
* Define which kind of erase page by page should be performed
*/
typedef enum {
ERASE_ALL = 0, /* /< erase all the pages */
SKIP_PANEL_INIT = 1, /* /< skip erase Panel Init Pages */
SKIP_PANEL_CX_INIT = 2 /* /< skip erase Panel Init and CX Pages */
} ErasePage;
/** @addtogroup fw_file
* @{
*/
/**
* Struct which contains information and data of the FW that should be burnt
*into the IC
*/
typedef struct {
u8 *data; /* /< pointer to an array of bytes which represent the
* FW data */
u16 fw_ver; /* /< FW version of the FW file */
u16 config_id; /* /< Config ID of the FW file */
u16 cx_ver; /* /< Cx version of the FW file */
u8 externalRelease[EXTERNAL_RELEASE_INFO_SIZE]; /* /< External Release
* Info of the FW file
* */
int data_size; /* /< dimension of data (the actual data to be burnt) */
u32 sec0_size; /* /< dimension of section 0 (FW) in .ftb file */
u32 sec1_size; /* /< dimension of section 1 (Config) in .ftb file */
u32 sec2_size; /* /< dimension of section 2 (Cx) in .ftb file */
u32 sec3_size; /* /< dimension of section 3 (TBD) in .ftb file */
u8 fw_code_size; /* /< size of fw code in pages in
.ftb file */
u8 panel_config_size;/* /< size of panel area in pages in
.ftb file */
u8 cx_area_size;/* /< size of cx area in pages in
.ftb file */
u8 fw_config_size;/* /< size of fw config in pages in
.ftb file */
u32 code_start_addr; /* start addr for fw code */
u32 cx_start_addr; /* start addr for cx area */
u32 config_start_addr; /* start addr for config area */
} Firmware;
/** @}*/
/** @addtogroup flash_command
* @{
*/
int wait_for_flash_ready(u8 type);
int hold_m3(void);
int flash_erase_unlock(void);
int flash_full_erase(void);
int flash_erase_page_by_page(ErasePage keep_cx, Firmware *fw);
int start_flash_dma(void);
int fillFlash(u32 address, u8 *data, int size);
int flash_unlock(void);
int getFWdata(const char *pathToFile, u8 **data, int *size);
int parseBinFile(u8 *fw_data, int fw_size, Firmware *fw, int keep_cx);
int readFwFile(const char *path, Firmware *fw, int keep_cx);
int flash_burn(Firmware fw, int force_burn, int keep_cx);
int flashProcedure(const char *path, int force, int keep_cx);
int flash_enable_uvlo_autopowerdown(void);
#endif
/** @}*/

View file

@ -0,0 +1,698 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting frames *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsFrame.c
* \brief Contains all the functions to work with frames
*/
#include "ftsCompensation.h"
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsFrame.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsSoftware.h"
#include "ftsTool.h"
#include "ftsTime.h"
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/serio.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/ctype.h>
extern SysInfo systemInfo; /* /< forward declaration of the global variable
* of containing System Info Data */
/**
* Read the channels lengths from the config memory
* @return OK if success or an error code which specify the type of error
*/
int getChannelsLength(void)
{
int ret;
u8 data[2];
if (data == NULL) {
logError(1, "%s getChannelsLength: ERROR %08X\n", tag,
ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = readConfig(ADDR_CONFIG_SENSE_LEN, data, 2);
if (ret < OK) {
logError(1, "%s getChannelsLength: ERROR %08X\n", tag, ret);
return ret;
}
systemInfo.u8_scrRxLen = (int)data[0];
systemInfo.u8_scrTxLen = (int)data[1];
logError(0, "%s Force_len = %d Sense_Len = %d\n", tag,
systemInfo.u8_scrTxLen, systemInfo.u8_scrRxLen);
return OK;
}
/**
* Read and pack the frame data related to the nodes
* @param address address in memory when the frame data node start
* @param size amount of data to read
* @param frame pointer to an array of bytes which will contain the frame node
*data
* @return OK if success or an error code which specify the type of error
*/
int getFrameData(u16 address, int size, short *frame)
{
int i, j, ret;
u8 *data = (u8 *)kmalloc(size * sizeof(u8), GFP_KERNEL);
if (data == NULL) {
logError(1, "%s getFrameData: ERROR %08X\n", tag, ERROR_ALLOC);
return ERROR_ALLOC;
}
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data,
size, DUMMY_FRAMEBUFFER);
if (ret < OK) {
logError(1, "%s getFrameData: ERROR %08X\n", tag, ERROR_BUS_R);
kfree(data);
return ERROR_BUS_R;
}
j = 0;
for (i = 0; i < size; i += 2) {
frame[j] = (short)((data[i + 1] << 8) + data[i]);
j++;
}
kfree(data);
return OK;
}
/**
* Return the number of Sense Channels (Rx)
* @return number of Rx channels
*/
int getSenseLen(void)
{
if (systemInfo.u8_scrRxLen == 0)
getChannelsLength();
return systemInfo.u8_scrRxLen;
}
/**
* Return the number of Force Channels (Tx)
* @return number of Tx channels
*/
int getForceLen(void)
{
if (systemInfo.u8_scrTxLen == 0)
getChannelsLength();
return systemInfo.u8_scrTxLen;
}
/******************** New API **************************/
/**
* Read a MS Frame from frame buffer memory
* @param type type of MS frame to read
* @param frame pointer to MutualSenseFrame variable which will contain the
* data
* @return > 0 if success specifying the number of node into the frame or
* an error code which specify the type of error
*/
int getMSFrame3(MSFrameType type, MutualSenseFrame *frame)
{
u16 offset;
int ret, force_len, sense_len;
force_len = getForceLen();
sense_len = getSenseLen();
frame->node_data = NULL;
logError(0, "%s %s: Starting to get frame %02X\n", tag, __func__,
type);
switch (type) {
case MS_RAW:
offset = systemInfo.u16_msTchRawAddr;
goto LOAD_NORM;
case MS_FILTER:
offset = systemInfo.u16_msTchFilterAddr;
goto LOAD_NORM;
case MS_STRENGTH:
offset = systemInfo.u16_msTchStrenAddr;
goto LOAD_NORM;
case MS_BASELINE:
offset = systemInfo.u16_msTchBaselineAddr;
LOAD_NORM:
if (force_len == 0 || sense_len == 0) {
logError(1,
"%s %s: number of channels not initialized ERROR %08X\n",
tag, __func__, ERROR_CH_LEN);
return ERROR_CH_LEN | ERROR_GET_FRAME;
}
break;
case MS_KEY_RAW:
offset = systemInfo.u16_keyRawAddr;
goto LOAD_KEY;
case MS_KEY_FILTER:
offset = systemInfo.u16_keyFilterAddr;
goto LOAD_KEY;
case MS_KEY_STRENGTH:
offset = systemInfo.u16_keyStrenAddr;
goto LOAD_KEY;
case MS_KEY_BASELINE:
offset = systemInfo.u16_keyBaselineAddr;
LOAD_KEY:
if (systemInfo.u8_keyLen == 0) {
logError(1,
"%s %s: number of channels not initialized ERROR %08X\n",
tag, __func__, ERROR_CH_LEN);
return ERROR_CH_LEN | ERROR_GET_FRAME;
}
force_len = 1;
sense_len = systemInfo.u8_keyLen;
break;
case FRC_RAW:
offset = systemInfo.u16_frcRawAddr;
goto LOAD_FRC;
case FRC_FILTER:
offset = systemInfo.u16_frcFilterAddr;
goto LOAD_FRC;
case FRC_STRENGTH:
offset = systemInfo.u16_frcStrenAddr;
goto LOAD_FRC;
case FRC_BASELINE:
offset = systemInfo.u16_frcBaselineAddr;
LOAD_FRC:
if (force_len == 0) {
logError(1,
"%s %s: number of channels not initialized ERROR %08X\n",
tag, __func__, ERROR_CH_LEN);
return ERROR_CH_LEN | ERROR_GET_FRAME;
}
sense_len = 1;
break;
default:
logError(1, "%s %s: Invalid type ERROR %08X\n", tag, __func__,
ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME);
return ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME;
}
frame->node_data_size = ((force_len) * sense_len);
frame->header.force_node = force_len;
frame->header.sense_node = sense_len;
frame->header.type = type;
logError(0, "%s %s: Force_len = %d Sense_len = %d Offset = %04X\n",
tag, __func__, force_len, sense_len, offset);
frame->node_data = (short *)kmalloc(frame->node_data_size *
sizeof(short), GFP_KERNEL);
if (frame->node_data == NULL) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_ALLOC |
ERROR_GET_FRAME);
return ERROR_ALLOC | ERROR_GET_FRAME;
}
ret = getFrameData(offset, frame->node_data_size * BYTES_PER_NODE,
(frame->node_data));
if (ret < OK) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__,
ERROR_GET_FRAME_DATA);
kfree(frame->node_data);
frame->node_data = NULL;
return ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
}
/* if you want to access one node i,j,
* compute the offset like: offset = i*columns + j = > frame[i, j] */
logError(0, "%s Frame acquired!\n", tag);
return frame->node_data_size;
/* return the number of data put inside frame */
}
/**
* Read a SS Frame from frame buffer
* @param type type of SS frame to read
* @param frame pointer to SelfSenseFrame variable which will contain the data
* @return > 0 if success specifying the number of node into frame or an
* error code which specify the type of error
*/
int getSSFrame3(SSFrameType type, SelfSenseFrame *frame)
{
u16 offset_force, offset_sense;
int ret;
frame->force_data = NULL;
frame->sense_data = NULL;
frame->header.force_node = getForceLen(); /* use getForce/SenseLen
* because introduce a
* recover mechanism in
* case of len =0 */
frame->header.sense_node = getSenseLen();
if (frame->header.force_node == 0 || frame->header.sense_node == 0) {
logError(1,
"%s %s: number of channels not initialized ERROR %08X\n",
tag,
__func__, ERROR_CH_LEN);
return ERROR_CH_LEN | ERROR_GET_FRAME;
}
logError(0, "%s %s: Starting to get frame %02X\n", tag, __func__,
type);
switch (type) {
case SS_RAW:
offset_force = systemInfo.u16_ssTchTxRawAddr;
offset_sense = systemInfo.u16_ssTchRxRawAddr;
break;
case SS_FILTER:
offset_force = systemInfo.u16_ssTchTxFilterAddr;
offset_sense = systemInfo.u16_ssTchRxFilterAddr;
break;
case SS_STRENGTH:
offset_force = systemInfo.u16_ssTchTxStrenAddr;
offset_sense = systemInfo.u16_ssTchRxStrenAddr;
break;
case SS_BASELINE:
offset_force = systemInfo.u16_ssTchTxBaselineAddr;
offset_sense = systemInfo.u16_ssTchRxBaselineAddr;
break;
case SS_HVR_RAW:
offset_force = systemInfo.u16_ssHvrTxRawAddr;
offset_sense = systemInfo.u16_ssHvrRxRawAddr;
break;
case SS_HVR_FILTER:
offset_force = systemInfo.u16_ssHvrTxFilterAddr;
offset_sense = systemInfo.u16_ssHvrRxFilterAddr;
break;
case SS_HVR_STRENGTH:
offset_force = systemInfo.u16_ssHvrTxStrenAddr;
offset_sense = systemInfo.u16_ssHvrRxStrenAddr;
break;
case SS_HVR_BASELINE:
offset_force = systemInfo.u16_ssHvrTxBaselineAddr;
offset_sense = systemInfo.u16_ssHvrRxBaselineAddr;
break;
case SS_PRX_RAW:
offset_force = systemInfo.u16_ssPrxTxRawAddr;
offset_sense = systemInfo.u16_ssPrxRxRawAddr;
break;
case SS_PRX_FILTER:
offset_force = systemInfo.u16_ssPrxTxFilterAddr;
offset_sense = systemInfo.u16_ssPrxRxFilterAddr;
break;
case SS_PRX_STRENGTH:
offset_force = systemInfo.u16_ssPrxTxStrenAddr;
offset_sense = systemInfo.u16_ssPrxRxStrenAddr;
break;
case SS_PRX_BASELINE:
offset_force = systemInfo.u16_ssPrxTxBaselineAddr;
offset_sense = systemInfo.u16_ssPrxRxBaselineAddr;
break;
case SS_DETECT_RAW:
if (systemInfo.u8_ssDetScanSet == 0) {
offset_force = systemInfo.u16_ssDetRawAddr;
offset_sense = 0;
frame->header.sense_node = 0;
} else {
offset_sense = systemInfo.u16_ssDetRawAddr;
offset_force = 0;
frame->header.force_node = 0;
}
break;
case SS_DETECT_FILTER:
if (systemInfo.u8_ssDetScanSet == 0) {
offset_force = systemInfo.u16_ssDetFilterAddr;
offset_sense = 0;
frame->header.sense_node = 0;
} else {
offset_sense = systemInfo.u16_ssDetFilterAddr;
offset_force = 0;
frame->header.force_node = 0;
}
break;
case SS_DETECT_BASELINE:
if (systemInfo.u8_ssDetScanSet == 0) {
offset_force = systemInfo.u16_ssDetBaselineAddr;
offset_sense = 0;
frame->header.sense_node = 0;
} else {
offset_sense = systemInfo.u16_ssDetBaselineAddr;
offset_force = 0;
frame->header.force_node = 0;
}
break;
case SS_DETECT_STRENGTH:
if (systemInfo.u8_ssDetScanSet == 0) {
offset_force = systemInfo.u16_ssDetStrenAddr;
offset_sense = 0;
frame->header.sense_node = 0;
} else {
offset_sense = systemInfo.u16_ssDetStrenAddr;
offset_force = 0;
frame->header.force_node = 0;
}
break;
default:
logError(1, "%s %s: Invalid type ERROR %08X\n", tag, __func__,
ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME);
return ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME;
}
frame->header.type = type;
logError(0,
"%s %s: Force_len = %d Sense_len = %d Offset_force = %04X Offset_sense = %04X\n",
tag, __func__, frame->header.force_node,
frame->header.sense_node,
offset_force, offset_sense);
frame->force_data = (short *)kmalloc(frame->header.force_node *
sizeof(short), GFP_KERNEL);
if (frame->force_data == NULL) {
logError(1, "%s %s: can not allocate force_data ERROR %08X\n",
tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME);
return ERROR_ALLOC | ERROR_GET_FRAME;
}
frame->sense_data = (short *)kmalloc(frame->header.sense_node *
sizeof(short), GFP_KERNEL);
if (frame->sense_data == NULL) {
kfree(frame->force_data);
frame->force_data = NULL;
logError(1, "%s %s: can not allocate sense_data ERROR %08X\n",
tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME);
return ERROR_ALLOC | ERROR_GET_FRAME;
}
ret = getFrameData(offset_force, frame->header.force_node *
BYTES_PER_NODE, (frame->force_data));
if (ret < OK) {
logError(1,
"%s %s: error while reading force data ERROR %08X\n",
tag,
__func__, ERROR_GET_FRAME_DATA);
kfree(frame->force_data);
frame->force_data = NULL;
kfree(frame->sense_data);
frame->sense_data = NULL;
return ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
}
ret = getFrameData(offset_sense, frame->header.sense_node *
BYTES_PER_NODE, (frame->sense_data));
if (ret < OK) {
logError(1,
"%s %s: error while reading sense data ERROR %08X\n",
tag,
__func__, ERROR_GET_FRAME_DATA);
kfree(frame->force_data);
frame->force_data = NULL;
kfree(frame->sense_data);
frame->sense_data = NULL;
return ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
}
/* 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 frame->header.force_node + frame->header.sense_node;
/* return the number of data put inside frame */
}
/**
* Read Initialization Data Header and check that the type loaded match with
* the one previously requested
* @param type type of Initialization data requested @link load_opt Load Host
* Data Option @endlink
* @param msHeader pointer to DataHeader variable which will contain the header
* info for the MS frame
* @param ssHeader pointer to DataHeader variable which will contain the header
* info for the SS frame
* @param address pointer to a variable which will contain the updated address
* to the next data
* @return OK if success or an error code which specify the type of error
*/
int readSyncDataHeader(u8 type, DataHeader *msHeader, DataHeader *ssHeader,
u64 *address)
{
u64 offset = ADDR_FRAMEBUFFER;
u8 data[SYNCFRAME_DATA_HEADER];
int ret;
ret = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, offset, data,
SYNCFRAME_DATA_HEADER, DUMMY_FRAMEBUFFER);
if (ret < OK) { /* i2c function have already a retry mechanism */
logError(1,
"%s %s: error while reading data header ERROR %08X\n",
tag,
__func__, ret);
return ret;
}
logError(0, "%s Read Data Header done!\n", tag);
if (data[0] != HEADER_SIGNATURE) {
logError(1,
"%s %s: The Header Signature was wrong! %02X != %02X ERROR %08X\n",
tag, __func__, data[0], HEADER_SIGNATURE,
ERROR_WRONG_DATA_SIGN);
return ERROR_WRONG_DATA_SIGN;
}
if (data[1] != type) {
logError(1, "%s %s: Wrong type found! %02X!=%02X ERROR %08X\n",
tag, __func__, data[1], type, ERROR_DIFF_DATA_TYPE);
return ERROR_DIFF_DATA_TYPE;
}
logError(0, "%s Type = %02X of SyncFrame data OK!\n", tag, type);
msHeader->force_node = data[5];
msHeader->sense_node = data[6];
logError(0, "%s MS Frame force_node = %d, sense_node = %d\n", tag,
msHeader->force_node, msHeader->sense_node);
ssHeader->force_node = data[7];
ssHeader->sense_node = data[8];
logError(0, "%s SS Frame force_node = %d, sense_node = %d\n", tag,
ssHeader->force_node, ssHeader->sense_node);
*address = offset + SYNCFRAME_DATA_HEADER + data[4];
return OK;
}
/**
* Read a Sync Frame from frame buffer which contain MS and SS data collected
*for the same scan
* @param type type of Sync frame to read, possible values:
* LOAD_SYNC_FRAME_RAW, LOAD_SYNC_FRAME_FILTER, LOAD_SYNC_FRAME_BASELINE,
* LOAD_SYNC_FRAME_STRENGTH
* @param msFrame pointer to MutualSenseFrame variable which will contain the
*MS data
* @param ssFrame pointer to SelfSenseFrame variable which will contain the SS
*data
* @return >0 if success specifying the total number of nodes copied into
* msFrame and ssFrame or an error code which specify the type of error
*/
int getSyncFrame(u8 type, MutualSenseFrame *msFrame, SelfSenseFrame *ssFrame)
{
int res;
u64 address;
msFrame->node_data = NULL;
ssFrame->force_data = NULL;
ssFrame->sense_data = NULL;
logError(0, "%s %s: Starting to get Sync Frame %02X...\n", tag,
__func__, type);
switch (type) {
case LOAD_SYNC_FRAME_RAW:
msFrame->header.type = MS_RAW;
ssFrame->header.type = SS_RAW;
break;
case LOAD_SYNC_FRAME_FILTER:
msFrame->header.type = MS_FILTER;
ssFrame->header.type = SS_FILTER;
break;
case LOAD_SYNC_FRAME_BASELINE:
msFrame->header.type = MS_BASELINE;
ssFrame->header.type = SS_BASELINE;
break;
case LOAD_SYNC_FRAME_STRENGTH:
msFrame->header.type = MS_STRENGTH;
ssFrame->header.type = SS_STRENGTH;
break;
default:
return ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME;
}
logError(0, "%s %s: Requesting Sync Frame %02X...\n", tag, __func__,
type);
res = requestSyncFrame(type);
if (res < OK) {
logError(1,
"%s %s: error while requesting Sync Frame ERROR %08X\n",
tag,
__func__, res | ERROR_GET_FRAME_DATA);
return res | ERROR_GET_FRAME_DATA;
}
res = readSyncDataHeader(type, &(msFrame->header), &(ssFrame->header),
&address);
if (res < OK) {
logError(1,
"%s %s: error while reading Sync Frame header... ERROR %08X\n",
tag, __func__, res | ERROR_GET_FRAME_DATA);
return res | ERROR_GET_FRAME_DATA;
}
msFrame->node_data_size = msFrame->header.force_node *
msFrame->header.sense_node;
msFrame->node_data = (short *)kmalloc(msFrame->node_data_size *
sizeof(short), GFP_KERNEL);
if (msFrame->node_data == NULL) {
logError(1,
"%s %s: impossible allocate memory for MS frame... ERROR %08X\n",
tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME);
return ERROR_ALLOC | ERROR_GET_FRAME;
}
logError(0, "%s %s: Getting MS frame at %04llX...\n", tag, __func__,
address);
res = getFrameData(address, (msFrame->node_data_size) * BYTES_PER_NODE,
(msFrame->node_data));
if (res < OK) {
logError(1, "%s %s: error while getting MS data...ERROR %08X\n",
tag, __func__, res);
res |= ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
goto ERROR;
}
/* move the offset */
address += (msFrame->node_data_size) * BYTES_PER_NODE;
ssFrame->force_data = (short *)kmalloc(ssFrame->header.force_node *
sizeof(short), GFP_KERNEL);
if (ssFrame->force_data == NULL) {
logError(1,
"%s %s: impossible allocate memory for SS force frame...ERROR %08X\n",
tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME);
res = ERROR_ALLOC | ERROR_GET_FRAME;
goto ERROR;
}
logError(0, "%s %s: Getting SS force frame at %04llX...\n", tag, __func__,
address);
res = getFrameData(address, (ssFrame->header.force_node) *
BYTES_PER_NODE, (ssFrame->force_data));
if (res < OK) {
logError(1,
"%s %s: error while getting SS force data...ERROR %08X\n",
tag,
__func__, res);
res |= ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
goto ERROR;
}
/* move the offset */
address += (ssFrame->header.force_node) * BYTES_PER_NODE;
ssFrame->sense_data = (short *)kmalloc(ssFrame->header.sense_node *
sizeof(short), GFP_KERNEL);
if (ssFrame->sense_data == NULL) {
logError(1,
"%s %s: impossible allocate memory for SS sense frame...ERROR %08X\n",
tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME);
res = ERROR_ALLOC | ERROR_GET_FRAME;
goto ERROR;
}
logError(0, "%s %s: Getting SS sense frame at %04llX...\n", tag, __func__,
address);
res = getFrameData(address, (ssFrame->header.sense_node) *
BYTES_PER_NODE, (ssFrame->sense_data));
if (res < OK) {
logError(1,
"%s %s: error while getting SS sense data...ERROR %08X\n",
tag,
__func__, res);
res |= ERROR_GET_FRAME_DATA | ERROR_GET_FRAME;
goto ERROR;
}
ERROR:
if (res < OK) {
if (msFrame->node_data != NULL) {
kfree(msFrame->node_data);
msFrame->node_data = NULL;
}
if (ssFrame->force_data != NULL) {
kfree(ssFrame->force_data);
ssFrame->force_data = NULL;
}
if (ssFrame->sense_data != NULL) {
kfree(ssFrame->sense_data);
ssFrame->sense_data = NULL;
}
logError(0, "Getting Sync Frame FAILED! ERROR %08X!\n", res);
} else {
logError(0, "Getting Sync Frame FINISHED!\n");
res = msFrame->node_data_size + ssFrame->header.force_node +
ssFrame->header.sense_node;
}
return res;
}

View file

@ -0,0 +1,114 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS functions for getting frames *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsFrame.h
* \brief Contains all the definitions and structs to work with frames
*/
#ifndef FTS_FRAME_H
#define FTS_FRAME_H
#include "ftsSoftware.h"
#include "ftsCore.h"
/* Number of data bytes for each node */
#define BYTES_PER_NODE 2 /* /< number of data bytes for each node */
#define RETRY_FRAME_DATA_READ 2 /* /< max number of attempts to read a
* frame */
#define SYNCFRAME_DATA_HEADER (DATA_HEADER + 12) /* /< number of bytes of
* Sync Frame Header */
/**
* Possible types of MS frames
*/
typedef enum {
MS_RAW = 0, /* /< Mutual Sense Raw Frame */
MS_FILTER = 1, /* /< Mutual Sense Filtered Frame */
MS_STRENGTH = 2, /* /< Mutual Sense Strength Frame (Baseline-Raw)
* */
MS_BASELINE = 3, /* /< Mutual Sense Baseline Frame */
MS_KEY_RAW = 4, /* /< Mutual Sense Key Raw Frame */
MS_KEY_FILTER = 5, /* /< Mutual Sense Key Filter Frame */
MS_KEY_STRENGTH = 6, /* /< Mutual Sense Key Strength Frame
* (Baseline-Raw) */
MS_KEY_BASELINE = 7, /* /< Mutual Sense Key Baseline Frame */
FRC_RAW = 8, /* /< Force Raw Frame */
FRC_FILTER = 9, /* /< Force Filtered Frame */
FRC_STRENGTH = 10, /* /< Force Strength Frame (Baseline-Raw) */
FRC_BASELINE = 11 /* /< Force Baseline Frame */
} MSFrameType;
/**
* Possible types of SS frames
*/
typedef enum {
SS_RAW = 0, /* /< Self Sense Raw Frame */
SS_FILTER = 1, /* /< Self Sense Filtered Frame */
SS_STRENGTH = 2, /* /< Self Sense Strength Frame (Baseline-Raw)
* */
SS_BASELINE = 3, /* /< Self Sense Baseline Frame */
SS_HVR_RAW = 4, /* /< Self Sense Hover Raw Frame */
SS_HVR_FILTER = 5, /* /< Self Sense Hover Filter Frame */
SS_HVR_STRENGTH = 6, /* /< Self Sense Hover Strength Frame
* (Baseline-Raw) */
SS_HVR_BASELINE = 7, /* /< Self Sense Hover Baseline Frame */
SS_PRX_RAW = 8, /* /< Self Sense Proximity Raw Frame */
SS_PRX_FILTER = 9, /* /< Self Sense Proximity Filtered Frame */
SS_PRX_STRENGTH = 10, /* /< Self Sense Proximity Strength Frame
* (Baseline-Raw) */
SS_PRX_BASELINE = 11, /* /< Self Sense Proximity Baseline Frame */
SS_DETECT_RAW = 12, /* /< Self Sense Detect Raw Frame */
SS_DETECT_FILTER = 13, /* /< Self Sense Detect Filter Frame */
SS_DETECT_STRENGTH = 14, /* /< Self Sense Detect Strength Frame */
SS_DETECT_BASELINE = 15 /* /< Self Sense Detect Baseline Frame */
} SSFrameType;
/**
* Struct which contains the data of a MS Frame
*/
typedef struct {
DataHeader header; /* /< Header which contain basic info of the
* frame */
short *node_data; /* /< Data of the frame */
int node_data_size; /* /< Dimension of the data of the frame */
} MutualSenseFrame;
/**
* Struct which contains the data of a SS Frame
*/
typedef struct {
DataHeader header; /* /< Header which contain basic info of the
* frame */
short *force_data; /* /< Force Channels Data */
short *sense_data; /* /< Sense Channels Data */
} SelfSenseFrame;
int getChannelsLength(void);
int getFrameData(u16 address, int size, short *frame);
int getSenseLen(void);
int getForceLen(void);
int getMSFrame3(MSFrameType type, MutualSenseFrame *frame);
int getSSFrame3(SSFrameType type, SelfSenseFrame *frame);
int getSyncFrame(u8 type, MutualSenseFrame *msFrame, SelfSenseFrame *ssFrame);
#endif

View file

@ -0,0 +1,405 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Gesture Utilities **
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsGesture.c
* \brief Contains all the functions and variable to handle the Gesture
*Detection features
*/
#include "ftsSoftware.h"
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsGesture.h"
#include "ftsIO.h"
#include "ftsTime.h"
#include "ftsTool.h"
/* /< store the gesture bitmask which the host want to enable.
* If bit set 1 the corresponding gesture will be detected in Gesture Mode */
static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 };
/* /< store the x coordinates of the points draw by the user
* when a gesture is detected */
u16 gesture_coordinates_x[GESTURE_MAX_COORDS_PAIRS_REPORT] = { 0 };
/* /< store the y coordinates of the points draw by the user
* when a gesture is detected */
u16 gesture_coordinates_y[GESTURE_MAX_COORDS_PAIRS_REPORT] = { 0 };
/* /< number of coordinates pairs (points) reported with the detected gesture */
int gesture_coords_reported = ERROR_OP_NOT_ALLOW;
static u8 refreshGestureMask; /* /< flag which indicate if there is
* the need to set the gesture mask in the FW */
struct mutex gestureMask_mutex; /* /< mutex used to control access on gesture
* shared variables */
/**
* Update the gesture mask stored in the driver and have to be used in gesture
* mode
* @param mask pointer to a byte array which store the gesture mask update
* that want to be performed.
* @param size dimension in byte of mask. This size can be <=
* GESTURE_MASK_SIZE.
* If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos
* and starting from the less significant byte.
* @param en 0 = enable the gestures set in mask, 1 = disable the gestures set
*in mask
* @return OK if success or an error code which specify the type of error
*/
int updateGestureMask(u8 *mask, int size, int en)
{
u8 temp;
int i;
if (mask != NULL) {
if (size <= GESTURE_MASK_SIZE) {
if (en == FEAT_ENABLE) {
mutex_lock(&gestureMask_mutex);
logError(0,
"%s updateGestureMask: setting gesture mask to enable...\n",
tag);
if (mask != NULL)
for (i = 0; i < size; i++)
gesture_mask[i] =
gesture_mask[i] |
mask[i];
/* back up of the gesture enabled */
refreshGestureMask = 1;
logError(0,
"%s updateGestureMask: gesture mask to enable SET!\n",
tag);
mutex_unlock(&gestureMask_mutex);
return OK;
} else if (en == FEAT_DISABLE) {
mutex_lock(&gestureMask_mutex);
logError(0,
"%s updateGestureMask: setting gesture mask to disable...\n",
tag);
for (i = 0; i < size; i++) {
temp = gesture_mask[i] ^ mask[i];
/* enabled XOR disabled */
gesture_mask[i] = temp &
gesture_mask[i];
/* temp AND enabled
* disable the gestures that were
* enabled */
}
logError(0,
"%s updateGestureMask: gesture mask to disable SET!\n",
tag);
refreshGestureMask = 1;
mutex_unlock(&gestureMask_mutex);
return OK;
} else {
logError(1,
"%s updateGestureMask: Enable parameter Invalid! %d != %d or %d ERROR %08X\n",
tag, en, FEAT_DISABLE, FEAT_ENABLE,
ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
} else {
logError(1,
"%s updateGestureMask: Size not valid! %d > %d ERROR %08X\n",
tag, size, GESTURE_MASK_SIZE,
ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
} else {
logError(1, "%s updateGestureMask: Mask NULL! ERROR %08X\n",
tag, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}
/**
* Enable in the FW the gesture mask to be used in gesture mode
* @param mask pointer to a byte array which store the gesture mask update
* that want to be sent to the FW, if NULL, will be used gesture_mask
* set previously without any changes.
* @param size dimension in byte of mask. This size can be <=
* GESTURE_MASK_SIZE.
* If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos and
* starting from the less significant byte.
* @return OK if success or an error code which specify the type of error
*/
int enableGesture(u8 *mask, int size)
{
int i, res;
logError(0, "%s Trying to enable gesture...\n", tag);
if (size <= GESTURE_MASK_SIZE) {
mutex_lock(&gestureMask_mutex);
if (mask != NULL)
for (i = 0; i < size; i++)
gesture_mask[i] = gesture_mask[i] | mask[i];
/* back up of the gesture enabled */
res = setFeatures(FEAT_SEL_GESTURE, gesture_mask,
GESTURE_MASK_SIZE);
if (res < OK) {
logError(1, "%s enableGesture: ERROR %08X\n", tag,
res);
goto END;
}
logError(0, "%s enableGesture DONE!\n", tag);
res = OK;
END:
mutex_unlock(&gestureMask_mutex);
return res;
} else {
logError(1,
"%s enableGesture: Size not valid! %d > %d ERROR %08X\n",
tag,
size, GESTURE_MASK_SIZE, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}
/**
* Disable in the FW the gesture mask to be used in gesture mode
* @param mask pointer to a byte array which store the gesture mask update that
* want to be sent to the FW, if NULL, all the gestures will be disabled.
* @param size dimension in byte of mask. This size can be <=
* GESTURE_MASK_SIZE.
* If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos and
* starting from the less significant byte.
* @return OK if success or an error code which specify the type of error
*/
int disableGesture(u8 *mask, int size)
{
u8 temp;
int i, res;
u8 *pointer;
logError(0, "%s Trying to disable gesture...\n", tag);
if (size <= GESTURE_MASK_SIZE) {
mutex_lock(&gestureMask_mutex);
if (mask != NULL) {
for (i = 0; i < size; i++) {
temp = gesture_mask[i] ^ mask[i];
/* enabled mask XOR disabled mask */
gesture_mask[i] = temp & gesture_mask[i];
/* temp AND enabled
* disable the gestures that are specified and
* previously enabled */
}
pointer = gesture_mask;
} else {
i = 0; /* if NULL is passed disable all the possible
* gestures */
pointer = (u8 *)&i;
}
res = setFeatures(FEAT_SEL_GESTURE, pointer, GESTURE_MASK_SIZE);
if (res < OK) {
logError(1, "%s disableGesture: ERROR %08X\n", tag,
res);
goto END;
}
logError(0, "%s disableGesture DONE!\n", tag);
res = OK;
END:
mutex_unlock(&gestureMask_mutex);
return res;
} else {
logError(1,
"%s disableGesture: Size not valid! %d > %d ERROR %08X\n",
tag,
size, GESTURE_MASK_SIZE, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}
/**
* Perform all the steps required to put the chip in gesture mode
* @param reload if set to 1, before entering in gesture mode it will re-enable
* in the FW the last defined gesture mask
* @return OK if success or an error code which specify the type of error
*/
int enterGestureMode(int reload)
{
int res, ret;
res = fts_disableInterrupt();
if (res < OK) {
logError(1, "%s enterGestureMode: ERROR %08X\n", tag, res |
ERROR_DISABLE_INTER);
return res | ERROR_DISABLE_INTER;
}
if (reload == 1 || refreshGestureMask == 1) {
res = enableGesture(NULL, 0);
if (res < OK) {
logError(1,
"%s enterGestureMode: enableGesture ERROR %08X\n",
tag,
res);
goto END;
}
refreshGestureMask = 0;
}
res = setScanMode(SCAN_MODE_LOW_POWER, 0);
if (res < OK) {
logError(1,
"%s enterGestureMode: enter gesture mode ERROR %08X\n",
tag,
res);
goto END;
}
res = OK;
END:
ret = fts_enableInterrupt();
if (ret < OK) {
logError(1,
"%s enterGestureMode: fts_enableInterrupt ERROR %08X\n",
tag,
res | ERROR_ENABLE_INTER);
res |= ret | ERROR_ENABLE_INTER;
}
return res;
}
/**
* Check if one or more Gesture IDs are currently enabled in gesture_mask
* @return FEAT_ENABLE if one or more gesture ids are enabled, FEAT_DISABLE if
* all the gesture ids are currently disabled
*/
int isAnyGestureActive(void)
{
int res = 0;
while (res < (GESTURE_MASK_SIZE - 1) && gesture_mask[res] == 0)
/* -1 because in any case the last gesture mask byte will
* be evaluated with the following if */
res++;
if (gesture_mask[res] != 0) {
logError(0,
"%s %s: Active Gestures Found! gesture_mask[%d] = %02X !\n",
tag, __func__, res, gesture_mask[res]);
return FEAT_ENABLE;
} else {
logError(0, "%s %s: All Gestures Disabled!\n", tag, __func__);
return FEAT_DISABLE;
}
}
/**
* Read from the frame buffer the gesture coordinates pairs of the points draw
* by an user when a gesture is detected
* @param event pointer to a byte array which contains the gesture event
* reported
* by the fw when a gesture is detected
* @return OK if success or an error code which specify the type of error
*/
int readGestureCoords(u8 *event)
{
int i = 0;
u64 address = 0;
int res;
u8 val[GESTURE_MAX_COORDS_PAIRS_REPORT * 4];
/* the max coordinates to read are GESTURE_COORDS_REPORT_MAX*4
* (because each coordinate is a short(*2) and we have x and y) */
if (event[0] == EVT_ID_USER_REPORT && event[1] ==
EVT_TYPE_USER_GESTURE) {
address = (event[4] << 8) | event[3]; /* Offset in framebuff */
gesture_coords_reported = event[5]; /* number of pairs
* coords reported */
if (gesture_coords_reported > GESTURE_MAX_COORDS_PAIRS_REPORT) {
logError(1,
"%s %s: FW reported more than %d points for the gestures! Decreasing to %d\n",
tag, __func__, gesture_coords_reported,
GESTURE_MAX_COORDS_PAIRS_REPORT);
gesture_coords_reported =
GESTURE_MAX_COORDS_PAIRS_REPORT;
}
logError(1, "%s %s: Offset: %08llX , coords pairs = %d\n", tag,
__func__, address, gesture_coords_reported);
res = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address,
val, (gesture_coords_reported * 2 * 2),
DUMMY_FRAMEBUFFER);
/* *2 because each coord is made by 2 bytes,
* *2 because there are x and y */
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++) {
gesture_coordinates_x[i] = (((u16)val[i * 2 + 1]) &
0x0F) << 8 |
(((u16)val[i * 2]) & 0xFF);
gesture_coordinates_y[i] =
(((u16)val[gesture_coords_reported * 2 + i * 2 + 1]) &
0x0F) << 8 |
(((u16)val[gesture_coords_reported * 2 +
i * 2]) & 0xFF);
}
logError(1, "%s %s: Reading Gesture Coordinates DONE!\n", tag,
__func__);
return OK;
} else {
logError(1,
"%s %s: The event passsed as argument is invalid! ERROR %08X\n",
tag, __func__, ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}
/**
* Return the coordinates of the points stored during the last detected gesture
* @param x output parameter which will store the address of the array
* containing the x coordinates
* @param y output parameter which will store the address of the array
* containing the y coordinates
* @return the number of points (x,y) stored and therefore the size of the x
* and y array returned.
*/
int getGestureCoords(u16 **x, u16 **y)
{
*x = gesture_coordinates_x;
*y = gesture_coordinates_y;
logError(1,
"%s %s: Number of gesture coordinates pairs returned = %d\n",
tag,
__func__, gesture_coords_reported);
return gesture_coords_reported;
}

View file

@ -0,0 +1,47 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Gesture Utilities *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsGesture.h
* \brief Contains all the macro and prototypes to handle the Gesture Detection
* features
*/
#ifndef FTS_GESTURE_H_
#define FTS_GESTURE_H_
#include "ftsHardware.h"
#define GESTURE_MASK_SIZE 4 /* /< number of bytes of the
* gesture mask */
#define GESTURE_MAX_COORDS_PAIRS_REPORT 100 /* /< max number of gestures
* coordinates pairs reported */
int updateGestureMask(u8 *mask, int size, int en);
int disableGesture(u8 *mask, int size);
int enableGesture(u8 *mask, int size);
int enterGestureMode(int reload);
int isAnyGestureActive(void);
int readGestureCoords(u8 *event);
int getGestureCoords(u16 **x, u16 **y);
#endif /* ! _GESTURE_H_ */

View file

@ -0,0 +1,308 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* HW related data *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsHardware.h
* \brief Contains all the definitions and information related to the IC
* from an hardware point of view
*/
#ifndef FTS_HARDWARE_H
#define FTS_HARDWARE_H
/* DIGITAL CHIP INFO */
//#define ALIX
#ifdef ALIX
#define DCHIP_ID_0 0x36 /* /< LSB chip ID for FTM5 */
#define DCHIP_ID_1 0x48 /* /< MSB chip ID for FTM5 */
#else
#define DCHIP_ID_0 0x36 /* /< LSB chip ID for FTM5 */
#define DCHIP_ID_1 0x39 /* /< MSB chip ID for FTM5 */
#endif
#define DCHIP_FW_VER_BYTE 2 /* /< number of bytes of the fw
* versions */
/* CHUNKS */
#define READ_CHUNK 1024 /* /< chunk dimension of
* a single i2c read,
* max allowed value is 2kB */
#define WRITE_CHUNK 1024 /* /< chunk dimension of
* a single i2c write,
* max allowed value is 2kB */
#define MEMORY_CHUNK 1024 /* /< chunk dimenasion of
* a single i2c write on mem,
* max allowed value is 2kB */
/* PROTOCOL INFO */
#define I2C_INTERFACE /*/< comment if the chip use SPI bus */
#ifdef I2C_INTERFACE
#define I2C_SAD 0x49 /* /< slave address of the IC */
#else
#define SPI4_WIRE /* /< comment if the master is SPI3 wires
* (MOSI and MISO share same line) */
#define SPI_DELAY_CS 10 /* /< time in usec to wait
* before rising the CS */
#define SPI_CLOCK_FREQ 7000000 /* /< clock frequency in Hz of
* the SPI bus */
#endif
#define IER_ENABLE 0x41 /* /< value to write in IER_ADDR
* to enable the interrupts */
#define IER_DISABLE 0x00 /* /< value to write in IER_ADDR
* to disable the interrupts */
/* FLASH COMMAND */
/** @defgroup flash_command Flash Commands
* All the commands that works with the flash of the IC
* @{
*/
#define FLASH_CMD_UNLOCK 0xF7
#define FLASH_CMD_READ_REGISTER 0xFA
#define FLASH_CMD_WRITE_REGISTER 0xFA
/* FLASH UNLOCK PARAMETER */
#define FLASH_UNLOCK_CODE0 0x25
#define FLASH_UNLOCK_CODE1 0x20
#define FLASH_UNLOCK_CODE2 0x6B
#define FLASH_UNLOCK_CODE3 0x00
/* FLASH UVLO ENABLE PARAMETER */
#define FLASH_UVLO_ENABLE_CODE0 0x1B
#define FLASH_UVLO_ENABLE_CODE1 0x66
/* FLASH AUTOPOWERDOWN ENABLE PARAMETER */
#define FLASH_AUTOPOWERDOWN_ENABLE_CODE0 0x68
#define FLASH_AUTOPOWERDOWN_ENABLE_CODE1 0x13
/* FLASH ERASE and DMA PARAMETER */
#define FLASH_ERASE_START 0x80
#define FLASH_ERASE_CODE1 0xC0
#define FLASH_DMA_CODE1 0xC0
#define FLASH_ERASE_UNLOCK_CODE0 0xDE
#define FLASH_ERASE_UNLOCK_CODE1 0x03
#define FLASH_ERASE_CODE0 0x6A
#define FLASH_DMA_CODE0 0x71
#define FLASH_DMA_CONFIG 0x72
#define FLASH_NUM_PAGE 32 /* /< number of pages in main
* flash */
#define FLASH_CX_PAGE_START 28 /* /< starting page which
* contain Cx data */
#define FLASH_CX_PAGE_END 30 /* /< last page which contain Cx
* data */
#define FLASH_PANEL_PAGE_START 26 /* /< starting page which
* contain Panel Init data */
#define FLASH_PANEL_PAGE_END 27 /* /< last page which contain
* Panel Init data */
/** @} */
/* FLASH ADDRESS */
#define FLASH_ADDR_CODE 0x00000000 /* /< starting address (words)
* in the flash of the code in
* FTI */
#define FLASH_ADDR_CONFIG 0x00007C00 /* /< starting address (words)
* in the flash of the config in
* FTI */
#define FLASH_ADDR_CX 0x00007000 /* /< starting address (words)
* in the flash of the Init data
* in FTI */
/* SIZES FW, CODE, CONFIG, MEMH */
/** @defgroup fw_file FW file info
* All the info related to the fw file
* @{
*/
#define FW_HEADER_SIZE 64 /* /< dimension of the header of the
* .fts file */
#define FW_HEADER_SIGNATURE 0xAA55AA55 /* /< header signature */
#define FW_FTB_VER 0x00000001 /* /< .ftb version */
#define FW_BYTES_ALLIGN 4 /* /< allignment of the info */
#define FW_BIN_VER_OFFSET 16 /* /< offset of the fw version in the
* .ftb file */
#define FW_BIN_CONFIG_ID_OFFSET 20 /* /< offset of the config id in the
* .ftb file */
#define FW_CX_VERSION (16 + 4) /* /< offset of CX version in
* the sec2 of FW file */
/** @} */
/* FIFO */
#define FIFO_EVENT_SIZE 8 /* /< number of bytes of one event */
#define FIFO_DEPTH 32 /* /< max number of events that the FIFO can
* collect before going in overflow in FTM5 */
#ifdef I2C_INTERFACE
#define FIFO_CMD_READALL 0x86 /* /< command to read all the events in
* the FIFO */
#else
#define FIFO_CMD_READALL 0x87 /* /< command to read all the events in
* the FIFO */
#endif
#define FIFO_CMD_READONE FIFO_CMD_READALL /* /< commad to read one
* event from FIFO */
/* OP CODES FOR MEMORY (based on protocol) */
#ifdef I2C_INTERFACE
#define FTS_CMD_HW_REG_R 0xFA /* /< command to read an hw register if
* FTI */
#define FTS_CMD_HW_REG_W 0xFA /* /< command to write an hw register if
* FTI */
#define FTS_CMD_FRAMEBUFFER_W 0xA6 /* /< command to write the framebuffer if
* FTI */
#define FTS_CMD_FRAMEBUFFER_R 0xA6 /* /< command to read the framebuffer if
* FTI */
#define FTS_CMD_CONFIG_R 0xA8 /* /< command to read the config memory
* if FTI */
#define FTS_CMD_CONFIG_W 0xA8 /* /< command to write the config memory
* if FTI */
#else
#define FTS_CMD_HW_REG_R 0xFB /* /< command to read an hw register if
* FTI */
#define FTS_CMD_HW_REG_W 0xFA /* /< command to write an hw register if
* FTI */
#define FTS_CMD_FRAMEBUFFER_W 0xA6 /* /< command to write the framebuffer if
* FTI */
#define FTS_CMD_FRAMEBUFFER_R 0xA7 /* /< command to read the framebuffer if
* FTI */
#define FTS_CMD_CONFIG_R 0xA9 /* /< command to read the config memory
* if FTI */
#define FTS_CMD_CONFIG_W 0xA8 /* /< command to write the config memory
* if FTI */
#endif
/* DUMMY BYTES DATA */
#ifndef I2C_INTERFACE
#define DUMMY_HW_REG 1 /* /< 1 if the first byte read from HW
* register is dummy */
#define DUMMY_FRAMEBUFFER 1 /* /< 1 if the first byte read from
* Frame buffer is dummy */
#define DUMMY_CONFIG 1 /* /< 1 if the first byte read from
* Config Memory is dummy */
#define DUMMY_FIFO 1 /* /< 1 if the first byte read from FIFO
* is dummy */
#else
#define DUMMY_HW_REG 0 /* /< 1 if the first byte read from HW
* register is dummy */
#define DUMMY_FRAMEBUFFER 0 /* /< 1 if the first byte read from
* Frame buffer is dummy */
#define DUMMY_CONFIG 0 /* /< 1 if the first byte read from
* Config Memory is dummy */
#define DUMMY_FIFO 0 /* /< 1 if the first byte read from FIFO
* is dummy */
#endif
/** @defgroup hw_adr HW Address
* @ingroup address
* Important addresses of hardware registers (and sometimes their important
*values)
* @{
*/
/* IMPORTANT HW ADDRESSES (u64) */
#define ADDR_FRAMEBUFFER ((u64)0x0000000000000000) /* /< frame buffer
* address in memory */
#define ADDR_ERROR_DUMP ((u64)0x000000000000EF80) /* /< start address
* dump error log */
/* SYSTEM RESET INFO */
#define ADDR_SYSTEM_RESET ((u64)0x0000000020000024) /* /< address of
* System control reg
* in FTI */
#define SYSTEM_RESET_VALUE 0x81 /* /< value to write in
* SYSTEM_RESET_ADDRESS to perform a
* system reset in FTM5 */
/* REMAP REGISTER */
#define ADDR_BOOT_OPTION ((u64)0x0000000020000025) /* /< address of Boot
* option register */
/* INTERRUPT INFO */
#define ADDR_IER ((u64)0x0000000020000029) /* /< address of the
* Interrupt enable
* register in FTMI */
/* Chip ID/Fw Version */
#define ADDR_DCHIP_ID ((u64)0x0000000020000000) /* /< chip id address
* for FTI */
#define ADDR_DCHIP_FW_VER ((u64)0x0000000020000004) /* /< fw version
* address for FTI */
/* INTERFACE REGISTER */
#define ADDR_ICR ((u64)0x000000002000002D) /* /< address of Device
* control register to
* set the comunication
* protocol (SPI/I2C) */
#define SPI4_MASK 0x02 /* /< bit to set spi4 */
/* CRC ADDR */
#define ADDR_CRC ((u64)0x0000000020000078) /* /< address of CRC
* control register in
* FTI */
#define CRC_MASK 0x03 /* /< bitmask which reveal if there is a
* CRC error in the flash */
#define ADDR_CONFIG_OFFSET ((u64)0x0000000000000000) /* /< config address
* in memory if FTI */
#define ADDR_GPIO_INPUT ((u64)0x0000000020000030) /* /< address of GPIO
* input register */
#define ADDR_GPIO_DIRECTION ((u64)0x0000000020000032) /* /< address of GPIO
* direction register */
#define ADDR_GPIO_PULLUP ((u64)0x0000000020000034) /* /< address of GPIO
* pullup register */
#define ADDR_GPIO_CONFIG_REG0 ((u64)0x000000002000003D) /* /< address of
* GPIO config register
*/
#define ADDR_GPIO_CONFIG_REG2 ((u64)0x000000002000003F) /* /< address of
* GPIO config register
*/
/**@}*/
#endif

View file

@ -0,0 +1,745 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* I2C/SPI Communication *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsIO.c
* \brief Contains all the functions which handle with the I2C/SPI
*communication
*/
#include "ftsSoftware.h"
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/of_gpio.h>
#ifdef I2C_INTERFACE
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
static u16 I2CSAD; /* /< slave address of the IC in the i2c bus */
#else
#include <linux/spi/spidev.h>
#endif
static void *client; /* /< bus client retrived by the OS and
* used to execute the bus transfers */
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsHardware.h"
#include "ftsIO.h"
/**
* Initialize the static client variable of the fts_lib library in order
* to allow any i2c/spi transaction in the driver (Must be called in the probe)
* @param clt pointer to i2c_client or spi_device struct which identify the bus
* slave device
* @return OK
*/
int openChannel(void *clt)
{
client = clt;
#ifdef I2C_INTERFACE
I2CSAD = ((struct i2c_client *)clt)->addr;
logError(1, "%s openChannel: SAD: %02X\n", tag, I2CSAD);
#else
logError(1, "%s %s: spi_master: flags = %04X !\n", tag, __func__,
((struct spi_device *)client)->master->flags);
logError(1,
"%s %s: spi_device: max_speed = %d chip select = %02X bits_per_words = %d mode = %04X !\n",
tag, __func__, ((struct spi_device *)client)->max_speed_hz,
((struct spi_device *)client)->chip_select,
((struct spi_device *)client)->bits_per_word,
((struct spi_device *)client)->mode);
logError(1, "%s openChannel: completed!\n", tag);
#endif
return OK;
}
#ifdef I2C_INTERFACE
/**
* Change the I2C slave address which will be used during the transaction
* (For Debug Only)
* @param sad new slave address id
* @return OK
*/
int changeSAD(u8 sad)
{
I2CSAD = sad;
return OK;
}
#endif
/**
* Retrieve the pointer to the device struct of the IC
* @return a the device struct pointer if client was previously set
* or NULL in all the other cases
*/
struct device *getDev(void)
{
if (client != NULL)
return &(getClient()->dev);
else
return NULL;
}
#ifdef I2C_INTERFACE
/**
* Retrieve the pointer of the i2c_client struct representing the IC as i2c
*slave
* @return client if it was previously set or NULL in all the other cases
*/
struct i2c_client *getClient()
{
if (client != NULL)
return (struct i2c_client *)client;
else
return NULL;
}
#else
/**
* Retrieve the pointer of the spi_device struct representing the IC as spi
*slave
* @return client if it was previously set or NULL in all the other cases
*/
struct spi_device *getClient()
{
if (client != NULL)
return (struct spi_device *)client;
else
return NULL;
}
#endif
/****************** New I2C API *********************/
/**
* Perform a direct bus read
* @param outBuf pointer of a byte array which should contain the byte read
*from the IC
* @param byteToRead number of bytes to read
* @return OK if success or an error code which specify the type of error
*/
int fts_read(u8 *outBuf, int byteToRead)
{
int ret = -1;
int retry = 0;
#ifdef I2C_INTERFACE
struct i2c_msg I2CMsg[1];
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)I2C_M_RD;
I2CMsg[0].len = (__u16)byteToRead;
I2CMsg[0].buf = (__u8 *)outBuf;
#else
struct spi_message msg;
struct spi_transfer transfer[1] = { { 0 } };
spi_message_init(&msg);
transfer[0].len = byteToRead;
transfer[0].delay_usecs = SPI_DELAY_CS;
transfer[0].tx_buf = NULL;
transfer[0].rx_buf = outBuf;
spi_message_add_tail(&transfer[0], &msg);
#endif
if (client == NULL)
return ERROR_BUS_O;
while (retry < I2C_RETRY && ret < OK) {
#ifdef I2C_INTERFACE
ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
#else
ret = spi_sync(getClient(), &msg);
#endif
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 %08X\n", tag, __func__, ERROR_BUS_R);
return ERROR_BUS_R;
}
return OK;
}
/**
* Perform a bus write followed by a bus read without a stop condition
* @param cmd byte array containing the command to write
* @param cmdLength size of cmd
* @param outBuf pointer of a byte array which should contain the bytes read
*from the IC
* @param byteToRead number of bytes to read
* @return OK if success or an error code which specify the type of error
*/
int fts_writeRead(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead)
{
int ret = -1;
int retry = 0;
#ifdef I2C_INTERFACE
struct i2c_msg I2CMsg[2];
/* write msg */
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = (__u8 *)cmd;
/* read msg */
I2CMsg[1].addr = (__u16)I2CSAD;
I2CMsg[1].flags = I2C_M_RD;
I2CMsg[1].len = byteToRead;
I2CMsg[1].buf = (__u8 *)outBuf;
#else
struct spi_message msg;
struct spi_transfer transfer[2] = { { 0 }, { 0 } };
spi_message_init(&msg);
transfer[0].len = cmdLength;
transfer[0].tx_buf = cmd;
transfer[0].rx_buf = NULL;
spi_message_add_tail(&transfer[0], &msg);
transfer[1].len = byteToRead;
transfer[1].delay_usecs = SPI_DELAY_CS;
transfer[1].tx_buf = NULL;
transfer[1].rx_buf = outBuf;
spi_message_add_tail(&transfer[1], &msg);
#endif
if (client == NULL)
return ERROR_BUS_O;
while (retry < I2C_RETRY && ret < OK) {
#ifdef I2C_INTERFACE
ret = i2c_transfer(getClient()->adapter, I2CMsg, 2);
#else
ret = spi_sync(getClient(), &msg);
#endif
retry++;
if (ret < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
return OK;
}
/**
* Perform a bus write
* @param cmd byte array containing the command to write
* @param cmdLength size of cmd
* @return OK if success or an error code which specify the type of error
*/
int fts_write(u8 *cmd, int cmdLength)
{
int ret = -1;
int retry = 0;
#ifdef I2C_INTERFACE
struct i2c_msg I2CMsg[1];
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = (__u8 *)cmd;
#else
struct spi_message msg;
struct spi_transfer transfer[1] = { { 0 } };
spi_message_init(&msg);
transfer[0].len = cmdLength;
transfer[0].delay_usecs = SPI_DELAY_CS;
transfer[0].tx_buf = cmd;
transfer[0].rx_buf = NULL;
spi_message_add_tail(&transfer[0], &msg);
#endif
if (client == NULL)
return ERROR_BUS_O;
while (retry < I2C_RETRY && ret < OK) {
#ifdef I2C_INTERFACE
ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
#else
ret = spi_sync(getClient(), &msg);
#endif
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 %08X\n", tag, __func__, ERROR_BUS_W);
return ERROR_BUS_W;
}
return OK;
}
/**
* Write a FW command to the IC and check automatically the echo event
* @param cmd byte array containing the command to send
* @param cmdLength size of cmd
* @return OK if success, or an error code which specify the type of error
*/
int fts_writeFwCmd(u8 *cmd, int cmdLength)
{
int ret = -1;
int ret2 = -1;
int retry = 0;
#ifdef I2C_INTERFACE
struct i2c_msg I2CMsg[1];
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)cmdLength;
I2CMsg[0].buf = (__u8 *)cmd;
#else
struct spi_message msg;
struct spi_transfer transfer[1] = { { 0 } };
spi_message_init(&msg);
transfer[0].len = cmdLength;
transfer[0].delay_usecs = SPI_DELAY_CS;
transfer[0].tx_buf = cmd;
transfer[0].rx_buf = NULL;
spi_message_add_tail(&transfer[0], &msg);
#endif
if (client == NULL)
return ERROR_BUS_O;
resetErrorList();
while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) {
#ifdef I2C_INTERFACE
ret = i2c_transfer(getClient()->adapter, I2CMsg, 1);
#else
ret = spi_sync(getClient(), &msg);
#endif
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 fts_writeFwCmd: ERROR %08X\n", tag,
ERROR_BUS_W);
return ERROR_BUS_W;
}
if (ret2 < OK) {
logError(1, "%s fts_writeFwCmd: check echo ERROR %08X\n", tag,
ret2);
return ret2;
}
return OK;
}
/**
* Perform two bus write and one bus read without any stop condition
* In case of FTI this function is not supported and the same sequence
* can be achieved calling fts_write followed by an fts_writeRead.
* @param writeCmd1 byte array containing the first command to write
* @param writeCmdLength size of writeCmd1
* @param readCmd1 byte array containing the second command to write
* @param readCmdLength size of readCmd1
* @param outBuf pointer of a byte array which should contain the bytes read
* from the IC
* @param byteToRead number of bytes to read
* @return OK if success or an error code which specify the type of error
*/
int fts_writeThenWriteRead(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, int
readCmdLength, u8 *outBuf, int byteToRead)
{
int ret = -1;
int retry = 0;
#ifdef I2C_INTERFACE
struct i2c_msg I2CMsg[3];
/* write msg */
I2CMsg[0].addr = (__u16)I2CSAD;
I2CMsg[0].flags = (__u16)0;
I2CMsg[0].len = (__u16)writeCmdLength;
I2CMsg[0].buf = (__u8 *)writeCmd1;
/* write msg */
I2CMsg[1].addr = (__u16)I2CSAD;
I2CMsg[1].flags = (__u16)0;
I2CMsg[1].len = (__u16)readCmdLength;
I2CMsg[1].buf = (__u8 *)readCmd1;
/* read msg */
I2CMsg[2].addr = (__u16)I2CSAD;
I2CMsg[2].flags = I2C_M_RD;
I2CMsg[2].len = byteToRead;
I2CMsg[2].buf = (__u8 *)outBuf;
#else
struct spi_message msg;
struct spi_transfer transfer[3] = { { 0 }, { 0 }, { 0 } };
spi_message_init(&msg);
transfer[0].len = writeCmdLength;
transfer[0].tx_buf = writeCmd1;
transfer[0].rx_buf = NULL;
spi_message_add_tail(&transfer[0], &msg);
transfer[1].len = readCmdLength;
transfer[1].tx_buf = readCmd1;
transfer[1].rx_buf = NULL;
spi_message_add_tail(&transfer[1], &msg);
transfer[2].len = byteToRead;
transfer[2].delay_usecs = SPI_DELAY_CS;
transfer[2].tx_buf = NULL;
transfer[2].rx_buf = outBuf;
spi_message_add_tail(&transfer[2], &msg);
#endif
if (client == NULL)
return ERROR_BUS_O;
while (retry < I2C_RETRY && ret < OK) {
#ifdef I2C_INTERFACE
ret = i2c_transfer(getClient()->adapter, I2CMsg, 3);
#else
ret = spi_sync(getClient(), &msg);
#endif
retry++;
if (ret < OK)
msleep(I2C_WAIT_BEFORE_RETRY);
}
if (ret < 0) {
logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
return OK;
}
/**
* Perform a chunked write with one byte op code and 1 to 8 bytes address
* @param cmd byte containing the op code to write
* @param addrSize address size in byte
* @param address the starting address
* @param data pointer of a byte array which contain the bytes to write
* @param dataSize size of data
* @return OK if success or an error code which specify the type of error
*/
/* this function works only if the address is max 8 bytes */
int fts_writeU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *data, int
dataSize)
{
u8 finalCmd[1 + addrSize + WRITE_CHUNK];
int remaining = dataSize;
int toWrite = 0, i = 0;
if (addrSize <= sizeof(u64)) {
while (remaining > 0) {
if (remaining >= WRITE_CHUNK) {
toWrite = WRITE_CHUNK;
remaining -= WRITE_CHUNK;
} else {
toWrite = remaining;
remaining = 0;
}
finalCmd[0] = cmd;
logError(0, "%s %s: addrSize = %d\n", tag, __func__,
addrSize);
for (i = 0; i < addrSize; i++) {
finalCmd[i + 1] = (u8)((address >> ((addrSize -
1 - i) *
8)) & 0xFF);
logError(1, "%s %s: cmd[%d] = %02X\n", tag,
__func__, i + 1, finalCmd[i + 1]);
}
memcpy(&finalCmd[addrSize + 1], data, toWrite);
if (fts_write(finalCmd, 1 + addrSize + toWrite) < OK) {
logError(1, "%s %s: ERROR %08X\n", tag,
__func__, ERROR_BUS_W);
return ERROR_BUS_W;
}
address += toWrite;
data += toWrite;
}
} else
logError(1,
"%s %s: address size bigger than max allowed %ld... ERROR %08X\n",
tag, __func__, sizeof(u64), ERROR_OP_NOT_ALLOW);
return OK;
}
/**
* Perform a chunked write read with one byte op code and 1 to 8 bytes address
* and dummy byte support.
* @param cmd byte containing the op code to write
* @param addrSize address size in byte
* @param address the starting address
* @param outBuf pointer of a byte array which contain the bytes to read
* @param byteToRead number of bytes to read
* @param hasDummyByte if the first byte of each reading is dummy (must be
* skipped)
* set to 1, otherwise if it is valid set to 0 (or any other value)
* @return OK if success or an error code which specify the type of error
*/
int fts_writeReadU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *outBuf, int
byteToRead, int hasDummyByte)
{
u8 finalCmd[1 + addrSize];
u8 buff[READ_CHUNK + 1];/* worst case has dummy byte */
int remaining = byteToRead;
int toRead = 0, i = 0;
while (remaining > 0) {
if (remaining >= READ_CHUNK) {
toRead = READ_CHUNK;
remaining -= READ_CHUNK;
} else {
toRead = remaining;
remaining = 0;
}
finalCmd[0] = cmd;
for (i = 0; i < addrSize; i++)
finalCmd[i + 1] = (u8)((address >> ((addrSize - 1 - i) *
8)) & 0xFF);
if (hasDummyByte == 1) {
if (fts_writeRead(finalCmd, 1 + addrSize, buff, toRead +
1) < OK) {
logError(1,
"%s %s: read error... ERROR %08X\n",
tag,
__func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
memcpy(outBuf, buff + 1, toRead);
} else {
if (fts_writeRead(finalCmd, 1 + addrSize, buff,
toRead) < OK) {
logError(1,
"%s %s: read error... ERROR %08X\n",
tag,
__func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
memcpy(outBuf, buff, toRead);
}
address += toRead;
outBuf += toRead;
}
return OK;
}
/**
* Perform a chunked write followed by a second write with one byte op code
* for each write and 1 to 8 bytes address (the sum of the 2 address size of
* the two writes can not exceed 8 bytes)
* @param cmd1 byte containing the op code of first write
* @param addrSize1 address size in byte of first write
* @param cmd2 byte containing the op code of second write
* @param addrSize2 address size in byte of second write
* @param address the starting address
* @param data pointer of a byte array which contain the bytes to write
* @param dataSize size of data
* @return OK if success or an error code which specify the type of error
*/
/* this function works only if the sum of two addresses in the two commands is
* max 8 bytes */
int fts_writeU8UXthenWriteU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, AddrSize
addrSize2, u64 address, u8 *data, int dataSize)
{
u8 finalCmd1[1 + addrSize1];
u8 finalCmd2[1 + addrSize2 + WRITE_CHUNK];
int remaining = dataSize;
int toWrite = 0, i = 0;
while (remaining > 0) {
if (remaining >= WRITE_CHUNK) {
toWrite = WRITE_CHUNK;
remaining -= WRITE_CHUNK;
} else {
toWrite = remaining;
remaining = 0;
}
finalCmd1[0] = cmd1;
for (i = 0; i < addrSize1; i++)
finalCmd1[i + 1] = (u8)((address >> ((addrSize1 +
addrSize2 - 1 -
i) * 8)) & 0xFF);
finalCmd2[0] = cmd2;
for (i = addrSize1; i < addrSize1 + addrSize2; i++)
finalCmd2[i - addrSize1 + 1] = (u8)((address >>
((addrSize1 +
addrSize2 - 1 -
i) * 8)) & 0xFF);
memcpy(&finalCmd2[addrSize2 + 1], data, toWrite);
if (fts_write(finalCmd1, 1 + addrSize1) < OK) {
logError(1, "%s %s: first write error... ERROR %08X\n",
tag, __func__, ERROR_BUS_W);
return ERROR_BUS_W;
}
if (fts_write(finalCmd2, 1 + addrSize2 + toWrite) < OK) {
logError(1,
"%s %s: second write error... ERROR %08X\n",
tag,
__func__, ERROR_BUS_W);
return ERROR_BUS_W;
}
address += toWrite;
data += toWrite;
}
return OK;
}
/**
* Perform a chunked write followed by a write read with one byte op code
* and 1 to 8 bytes address for each write and dummy byte support.
* @param cmd1 byte containing the op code of first write
* @param addrSize1 address size in byte of first write
* @param cmd2 byte containing the op code of second write read
* @param addrSize2 address size in byte of second write read
* @param address the starting address
* @param outBuf pointer of a byte array which contain the bytes to read
* @param byteToRead number of bytes to read
* @param hasDummyByte if the first byte of each reading is dummy (must be
* skipped) set to 1,
* otherwise if it is valid set to 0 (or any other value)
* @return OK if success or an error code which specify the type of error
*/
/* this function works only if the sum of two addresses in the two commands is
* max 8 bytes */
int fts_writeU8UXthenWriteReadU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2,
AddrSize addrSize2, u64 address, u8 *outBuf,
int byteToRead, int hasDummyByte)
{
u8 finalCmd1[1 + addrSize1];
u8 finalCmd2[1 + addrSize2];
u8 buff[READ_CHUNK + 1];/* worst case has dummy byte */
int remaining = byteToRead;
int toRead = 0, i = 0;
while (remaining > 0) {
if (remaining >= READ_CHUNK) {
toRead = READ_CHUNK;
remaining -= READ_CHUNK;
} else {
toRead = remaining;
remaining = 0;
}
finalCmd1[0] = cmd1;
for (i = 0; i < addrSize1; i++)
finalCmd1[i + 1] = (u8)((address >> ((addrSize1 +
addrSize2 - 1 -
i) * 8)) & 0xFF);
/* logError(1, "%s %s: finalCmd1[%d] = %02X\n",
* tag, __func__, i+1, finalCmd1[i + 1]); */
finalCmd2[0] = cmd2;
for (i = addrSize1; i < addrSize1 + addrSize2; i++)
finalCmd2[i - addrSize1 + 1] = (u8)((address >>
((addrSize1 +
addrSize2 - 1 -
i) * 8)) & 0xFF);
if (fts_write(finalCmd1, 1 + addrSize1) < OK) {
logError(1, "%s %s: first write error... ERROR %08X\n",
tag, __func__, ERROR_BUS_W);
return ERROR_BUS_W;
}
if (hasDummyByte == 1) {
if (fts_writeRead(finalCmd2, 1 + addrSize2, buff,
toRead + 1) < OK) {
logError(1,
"%s %s: read error... ERROR %08X\n",
tag,
__func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
memcpy(outBuf, buff + 1, toRead);
} else {
if (fts_writeRead(finalCmd2, 1 + addrSize2, buff,
toRead) < OK) {
logError(1,
"%s %s: read error... ERROR %08X\n",
tag,
__func__, ERROR_BUS_WR);
return ERROR_BUS_WR;
}
memcpy(outBuf, buff, toRead);
}
address += toRead;
outBuf += toRead;
}
return OK;
}

View file

@ -0,0 +1,66 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* I2C/SPI Communication *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsIO.h
* \brief Contains all the definitions and prototypes used and implemented in
* ftsIO.c
*/
#ifndef FTS_IO_H
#define FTS_IO_H
#include "ftsSoftware.h"
#define I2C_RETRY 3 /* /< number of retry in case of i2c
* failure */
#define I2C_WAIT_BEFORE_RETRY 2 /* /< wait in ms before retry an i2c
* transaction */
#ifdef I2C_INTERFACE
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
struct i2c_client *getClient(void);
#else
#include <linux/spi/spi.h>
struct spi_device *getClient(void);
#endif
int openChannel(void *clt);
struct device *getDev(void);
/*************** NEW I2C API ****************/
#ifdef I2C_INTERFACE
int changeSAD(u8 sad);
#endif
int fts_read(u8 *outBuf, int byteToRead);
int fts_writeRead(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead);
int fts_write(u8 *cmd, int cmdLength);
int fts_writeFwCmd(u8 *cmd, int cmdLenght);
int fts_writeThenWriteRead(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, int
readCmdLength, u8 *outBuf, int byteToRead);
int fts_writeU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *data, int
dataSize);
int fts_writeReadU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *outBuf, int
byteToRead, int hasDummyByte);
int fts_writeU8UXthenWriteU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, AddrSize
addrSize2, u64 address, u8 *data, int dataSize);
int fts_writeU8UXthenWriteReadU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2,
AddrSize addrSize2, u64 address, u8 *outBuf,
int count, int hasDummyByte);
#endif

View file

@ -0,0 +1,512 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FW related data *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsSoftware.h
* \brief Contains all the definitions and information related to the IC from a
*fw/driver point of view
*/
#ifndef FTS_SOFTWARE_H
#define FTS_SOFTWARE_H
#include <linux/types.h>
#include "ftsHardware.h"
/* unsigned types */
typedef uint8_t u8; /* /< basic type that represent one byte (or 8 bits) */
typedef uint16_t u16; /* /< basic type that represent 2 bytes (or 16 bits) */
typedef uint32_t u32; /* /< basic type that represent 4 bytes (or 32 bits) */
typedef uint64_t u64; /* /< basic type that represent 8 bytes (or 64 bits) */
/* signed type */
typedef signed char i8; /* /< basic type that represent one signed byte (or 8
* bits) */
/**
* Enumerator which contains all the possible address length expressed in
*bytes.
*/
typedef enum {
NO_ADDR = 0,
BITS_8 = 1,
BITS_16 = 2,
BITS_24 = 3,
BITS_32 = 4,
BITS_40 = 5,
BITS_48 = 6,
BITS_56 = 7,
BITS_64 = 8
} AddrSize;
/******************** NEW API *********************/
/* HOST COMMAND */
/** @defgroup host_command Fw Host op codes
* Valid op codes for fw commands
* @{
*/
/** @defgroup scan_mode Scan Mode
* @ingroup host_command
* Set the scanning mode required according to the parameters
* @{
*/
#define FTS_CMD_SCAN_MODE 0xA0 /* /< OP Code to set scan mode */
/** @} */
/** @defgroup feat_sel Feature Select
* @ingroup host_command
* Set the system defined features to enable/disable according the parameters
* @{
*/
#define FTS_CMD_FEATURE 0xA2 /* /< OP code to set features */
/** @} */
/** @defgroup sys_cmd System Command
* @ingroup host_command
* Execute a system command to perform core tasks
* @{
*/
#define FTS_CMD_SYSTEM 0xA4 /* /< OP code to write s system command
* */
/** @} */
/** @} */ /* end host_command group */
/* SCAN MODE OPTION (0xA0) */
/* Scan mode selection */
/** @defgroup scan_opt Scan Mode Option
* @ingroup scan_mode
* Valid scanning modes and their options
* @{
*/
#define SCAN_MODE_ACTIVE 0x00 /* /< Select the Active scanning mode */
#define SCAN_MODE_LOW_POWER 0x01 /* /< Select the low power scanning mode
* */
#define SCAN_MODE_JIG_1 0x02 /* /< Select the Jig test 1 */
#define SCAN_MODE_LOCKED 0x03 /* /< Select the Scan mode which will be
* locked */
/** @}*/
/* Active mode option (bitmask) */
/** @defgroup active_bitmask Active Mode Bitmask
* @ingroup scan_opt
* Bitmask to use to enables the specific scanning with the SCAN_MODE_ACTIVE
*option
* @{
*/
#define ACTIVE_MULTI_TOUCH 0x01 /* /< Bit 0 MS/SS scan */
#define ACTIVE_KEY 0x02 /* /< Bit 1 Key scan */
#define ACTIVE_HOVER 0x04 /* /< Bit 2 Hover scan */
#define ACTIVE_PROXIMITY 0x08 /* /< Bit 3 Proximity scan */
#define ACTIVE_FORCE 0x10 /* /< Bit 4 Force scan */
/** @}*/
/* Locked mode option (locked mode) */
/** @defgroup locked_opt Locked Mode Option
* @ingroup scan_opt
* Options to enable and lock specific scanning with the SCAN_MODE_LOCKED
*option
* @{
*/
#define LOCKED_ACTIVE 0x00 /* /< Active Scan Mode */
#define LOCKED_HOVER 0x01 /* /< Hover Scan Mode */
#define LOCKED_IDLE 0x02 /* /< Idle Scan Mode */
#define LOCKED_LP_DETECT 0x10 /* /< Low Power SS */
#define LOCKED_LP_ACTIVE 0x11 /* /< Low Power MS */
/** @}*/
/* FEATURE SELECT OPTION (0xA2) */
/* Feature Selection */
/** @defgroup feat_opt Feature Selection Option
* @ingroup feat_sel
* System defined features that can be enable/disable
* @{
*/
#define FEAT_SEL_GLOVE 0x00 /* /< Glove Mode */
#define FEAT_SEL_COVER 0x01 /* /< Cover Mode */
#define FEAT_SEL_CHARGER 0x02 /* /< Charger Mode */
#define FEAT_SEL_GESTURE 0x03 /* /< Gesture Mode */
#define FEAT_SEL_GRIP 0x04 /* /< Grip Detection */
#define FEAT_SEL_STYLUS 0x07 /* /< Stylus Mode
* (this is a driver define, not
* available in FW) */
/** @}*/
/* Feature Settings */
#define FEAT_ENABLE 1 /* /< General value to enable a feature
* */
#define FEAT_DISABLE 0 /* /< General value to disable a feature
* */
/* Charger */
/** @defgroup charger_opt Charger Mode Option
* @ingroup feat_sel
* Option for Charger Mode, it is a bitmask where the each bit indicate a
*different kind of chager
* @{
*/
#define CHARGER_CABLE 0x01 /* /< normal usb charger */
#define CHARGER_WIRLESS 0x02 /* /< wireless charger */
/** @}*/
/* Gestures */
/** @defgroup gesture_opt Gesture Mode Option
* @ingroup feat_sel
* Gesture IDs of the predefined gesture recognized by the fw.
* The ID represent also the position of the corresponding bit in the gesture
*mask
* @{
*/
#define GEST_ID_UP_1F 0x01 /* /< Bottom to Top line */
#define GEST_ID_DOWN_1F 0x02 /* /< Top to bottom line */
#define GEST_ID_LEFT_1F 0x03 /* /< Right to left line */
#define GEST_ID_RIGHT_1F 0x04 /* /< Left to right line */
#define GEST_ID_DBLTAP 0x05 /* /< Double Tap */
#define GEST_ID_O 0x06 /* /< 'O' */
#define GEST_ID_C 0x07 /* /< 'C' */
#define GEST_ID_M 0x08 /* /< 'M' */
#define GEST_ID_W 0x09 /* /< 'W' */
#define GEST_ID_E 0x0A /* /< 'e' */
#define GEST_ID_L 0x0B /* /< 'L' */
#define GEST_ID_F 0x0C /* /< 'F' */
#define GEST_ID_V 0x0D /* /< 'V' */
#define GEST_ID_AT 0x0E /* /< '@' */
#define GEST_ID_S 0x0F /* /< 'S' */
#define GEST_ID_Z 0x10 /* /< 'Z' */
#define GEST_ID_LEFTBRACE 0x11 /* /< '<' */
#define GEST_ID_RIGHTBRACE 0x12 /* /< '>' */
#define GEST_ID_CARET 0x13 /* /< '^' */
/** @}*/
/* WRYTE SYSTEM COMMAND (0xA4) */
/* System command */
/** @defgroup sys_opt System Command Option
* @ingroup sys_cmd
* Valid System Command Parameters
* @{
*/
#define SYS_CMD_SPECIAL 0x00 /* /< Special Commands */
#define SYS_CMD_INT 0x01 /* /< FW Interrupt Control */
#define SYS_CMD_FORCE_CAL 0x02 /* /< Force Calibration */
#define SYS_CMD_CX_TUNING 0x03 /* /< CX initialization */
#define SYS_CMD_ITO 0x04 /* /< ITO test */
#define SYS_CMD_SAVE_FLASH 0x05 /* /< Saving to flash */
#define SYS_CMD_LOAD_DATA 0x06 /* /< Load Host data memory */
#define SYS_CMD_SPECIAL_TUNING 0x08 /* /< Perform some special tuning */
#define SYS_CMD_MP_FLAG 0x0C /* /< Update value of MP flag in RAM */
/** @} */
/* System command settings */
/* Special commands */
/** @defgroup sys_special_opt Special Command Option
* @ingroup sys_cmd
* Valid special command
* @{
*/
#define SPECIAL_SYS_RESET 0x00 /* /< System Reset triggered by the FW */
#define SPECIAL_FIFO_FLUSH 0x01 /* /< Flush of the FIFO */
#define SPECIAL_PANEL_INIT 0x02 /* /< Panel Initialization */
#define SPECIAL_FULL_PANEL_INIT 0x03 /* /< Full panel initialization */
/** @} */
/* Force Cal and Cx auto tuning */
/** @defgroup forcecal_cx_opt Force Cal and Tuning Option
* @ingroup sys_cmd
* Valid bitmask for triggering forcecal or performing manual autotune
* @{
*/
#define CAL_MS_TOUCH 0x01 /* /< Mutual Sense Touch */
#define CAL_MS_LOW_POWER 0x02 /* /< Mutual Sense Touch in low power
* mode */
#define CAL_SS_TOUCH 0x04 /* /< Self Sense Touch */
#define CAL_SS_IDLE 0x08 /* /< Self Sense Touch in idle mode */
#define CAL_MS_KEY 0x10 /* /< Mutual Sense Key */
#define CAL_SS_KEY 0x20 /* /< Self Sense Key */
#define CAL_MS_FORCE 0x40 /* /< Mutual Sense Force */
#define CAL_SS_FORCE 0x80 /* /< Self Sense Force */
/** @} */
/* ITO checks (position of the bit in the mask) */
/** @defgroup ito_opt ITO Test Option
* @ingroup sys_cmd
* Valid option for the ITO test
* @{
*/
#define ITO_FORCE_OPEN 0x00 /* /< Check if some force channels is
* open */
#define ITO_SENSE_OPEN 0x01 /* /< Check if some sense channels is
* open */
#define ITO_FORCE_GROUND 0x02 /* /< Check if some force channels is
* short to ground */
#define ITO_SENSE_GROUND 0x03 /* /< Check if some sense channels is
* short to ground */
#define ITO_FORCE_VDD 0x04 /* /< Check if some force channels is
* short to VDD */
#define ITO_SENSE_VDD 0x05 /* /< Check if some sense channels is
* short to VDD */
#define ITO_FORCE_FORCE 0x06 /* /< Check force to force channels */
#define ITO_FORCE_SENSE 0x07 /* /< Check force to sense channels */
#define ITO_SENSE_SENSE 0x08 /* /< Check sense to sense channels */
#define ITO_KEY_FORCE_OPEN 0x09 /* /< Check if some force channels used
* for the key is open */
#define ITO_KEY_SENSE_OPEN 0x0A /* /< Check if some sense channels used
* for the key is open */
/** @}*/
/* Save flash */
/** @defgroup save_opt Save to Flash Option
* @ingroup sys_cmd
* Valid option for saving data to the Flash
* @{
*/
#define SAVE_FW_CONF 0x01 /* /< Save the confing to the flash */
#define SAVE_CX 0x02 /* /< Save the CX to the flash */
#define SAVE_PANEL_CONF 0x04 /* /< Save the Panel configuration to the flash
* */
/** @}*/
/* Load Data */
/** @defgroup load_opt Load Host Data Option
* @ingroup sys_cmd
* Valid option to ask to the FW to load host data into the memory
* @{
*/
#define LOAD_SYS_INFO 0x01 /* /< Load System Info */
#define LOAD_CX_MS_TOUCH 0x10 /* /< Load MS Init Data for
* Active Mode */
#define LOAD_CX_MS_LOW_POWER 0x11 /* /< Load MS Init Data for Low
* Power Mode */
#define LOAD_CX_SS_TOUCH 0x12 /* /< Load SS Init Data for
* Active Mode */
#define LOAD_CX_SS_TOUCH_IDLE 0x13 /* /< Load SS Init Data for Low
* Power Mode */
#define LOAD_CX_MS_KEY 0x14 /* /< Load MS Init Data for Key
* */
#define LOAD_CX_SS_KEY 0x15 /* /< Load SS Init Data for Key
* */
#define LOAD_CX_MS_FORCE 0x16 /* /< Load MS Init Data for
* Force */
#define LOAD_CX_SS_FORCE 0x17 /* /< Load SS Init Data for
* Force */
#define LOAD_SYNC_FRAME_RAW 0x30 /* /< Load a Synchronized Raw
* Frame */
#define LOAD_SYNC_FRAME_FILTER 0x31 /* /< Load a Synchronized Filter
* Frame */
#define LOAD_SYNC_FRAME_STRENGTH 0x33 /* /< Load a Synchronized
* Strength Frame */
#define LOAD_SYNC_FRAME_BASELINE 0x32 /* /< Load a Synchronized
* Baseline Frame */
#define LOAD_PANEL_CX_TOT_MS_TOUCH 0x50 /* /< Load TOT MS Init Data for
* Active Mode */
#define LOAD_PANEL_CX_TOT_MS_LOW_POWER 0x51 /* /< Load TOT MS Init Data for
* Low Power Mode */
#define LOAD_PANEL_CX_TOT_SS_TOUCH 0x52 /* /< Load TOT SS Init Data for
* Active Mode */
#define LOAD_PANEL_CX_TOT_SS_TOUCH_IDLE 0x53 /* /< Load TOT SS Init Data for
* Low Power Mode */
#define LOAD_PANEL_CX_TOT_MS_KEY 0x54 /* /< Load TOT MS Init Data for
* Key */
#define LOAD_PANEL_CX_TOT_SS_KEY 0x55 /* /< Load TOT SS Init Data for
* Key */
#define LOAD_PANEL_CX_TOT_MS_FORCE 0x56 /* /< Load TOT MS Init Data for
* Force */
#define LOAD_PANEL_CX_TOT_SS_FORCE 0x57 /* /< Load TOT SS Init Data for
* Force */
/** @}*/
/* Special Tuning */
/** @defgroup spcl_tun_opt Special Tuning Option
* @ingroup sys_cmd
* Valid special tuning operations which the fw can perform (bitmask)
* @{
*/
#define SPECIAL_TUNING_LP_TIMER 0x01 /* /< Perform LP Timer calibration */
#define SPECIAL_TUNING_IOFF 0x02 /* /< Perform Ioff calibration */
/** @}*/
/* EVENT ID */
/** @defgroup events_group FW Event IDs and Types
* Event IDs and Types pushed by the FW into the FIFO
* @{
*/
#define EVT_ID_NOEVENT 0x00 /* /< No Events */
#define EVT_ID_CONTROLLER_READY 0x03 /* /< Controller ready, issued after a
system reset. */
#define EVT_ID_ENTER_POINT 0x13 /* /< Touch enter in the sensing area */
#define EVT_ID_MOTION_POINT 0x23 /* /< Touch motion (a specific touch
* changed position) */
#define EVT_ID_LEAVE_POINT 0x33 /* /< Touch leave the sensing area */
#define EVT_ID_STATUS_UPDATE 0x43 /* /< FW report a system condition
* change */
#define EVT_ID_USER_REPORT 0x53 /* /< User related events triggered
* (keys, gestures, proximity etc) */
#define EVT_ID_DEBUG 0xE3 /* /< Debug Info */
#define EVT_ID_ERROR 0xF3 /* /< Error Event */
/* /< Max number of unique event IDs supported */
#define NUM_EVT_ID (((EVT_ID_ERROR & 0xF0) >> 4)+1)
/** @}*/
/* STATUS TYPE */
/** @defgroup status_type Status Event Types
* @ingroup events_group
* Types of EVT_ID_STATUS_UPDATE events
* @{
*/
#define EVT_TYPE_STATUS_ECHO 0x01 /* /< Echo event, contain the
* first 5 bytes of the FW
* command sent */
#define EVT_TYPE_STATUS_FRAME_DROP 0x03 /* /< Some frame was skipped
* during the elaboration */
#define EVT_TYPE_STATUS_FORCE_CAL 0x05 /* /< Force Calibration has
* triggered */
#define EVT_TYPE_STATUS_WATER 0x06 /* /< Water Mode */
#define EVT_TYPE_STATUS_SS_RAW_SAT 0x07 /* /< Self Sense data saturated
* */
/** @} */
/* USER TYPE */
/** @defgroup user_type User Event Types
* @ingroup events_group
* Types of EVT_ID_USER_REPORT events generated by the FW
* @{
*/
#define EVT_TYPE_USER_KEY 0x00 /* /< Keys pressed/relesed event report
* */
#define EVT_TYPE_USER_PROXIMITY 0x01 /* /< Proximity detection event report
* */
#define EVT_TYPE_USER_GESTURE 0x02 /* /< Gesture detection event report */
/** @}*/
/* ERROR TYPE */
/** @defgroup error_type Error Event Types
* @ingroup events_group
* Types of EVT_ID_ERROR events reported by the FW
* @{
*/
#define EVT_TYPE_ERROR_HARD_FAULT 0x02 /* /< Hard Fault */
#define EVT_TYPE_ERROR_WATCHDOG 0x06 /* /< Watchdog timer expired */
#define EVT_TYPE_ERROR_CRC_CFG_HEAD 0x20 /* /< CRC error in the Config
* Area Header */
#define EVT_TYPE_ERROR_CRC_CFG 0x21 /* /< CRC error in the Config
* Area */
#define EVT_TYPE_ERROR_CRC_PANEL_HEAD 0x22 /* /< CRC error in the Panel
* Area Header */
#define EVT_TYPE_ERROR_CRC_PANEL 0x23 /* /< CRC error in the Panel
* Area */
#define EVT_TYPE_ERROR_ITO_FORCETOGND 0x60 /* /< Force channel/s short to
* ground */
#define EVT_TYPE_ERROR_ITO_SENSETOGND 0x61 /* /< Sense channel/s short to
* ground */
#define EVT_TYPE_ERROR_ITO_FORCETOVDD 0x62 /* /< Force channel/s short to
* VDD */
#define EVT_TYPE_ERROR_ITO_SENSETOVDD 0x63 /* /< Sense channel/s short to
* VDD */
#define EVT_TYPE_ERROR_ITO_FORCE_P2P 0x64 /* /< Pin to Pin short Force
* channel/s */
#define EVT_TYPE_ERROR_ITO_SENSE_P2P 0x65 /* /< Pin to Pin short Sense
* channel/s */
#define EVT_TYPE_ERROR_ITO_FORCEOPEN 0x66 /* /< Force Panel open */
#define EVT_TYPE_ERROR_ITO_SENSEOPEN 0x67 /* /< Sense Panel open */
#define EVT_TYPE_ERROR_ITO_KEYOPEN 0x68 /* /< Key open */
#define EVT_TYPE_ERROR_CRC_CX_HEAD 0xA0 /* /< CRC error in the CX Area
* Header */
#define EVT_TYPE_ERROR_CRC_CX 0xA1 /* /< CRC error in the CX Area
* */
#define EVT_TYPE_ERROR_CRC_CX_SUB_HEAD 0xA5 /* /< CRC error in the CX
* Subsection Area Header */
#define EVT_TYPE_ERROR_CRC_CX_SUB 0xA6 /* /< CRC error in the CX
* Subsection Area */
#define EVT_TYPE_ERROR_ESD 0xF0 /* /< ESD error */
/** @}*/
/** @defgroup address Chip Address
* Collection of HW and SW Addresses useful to collect different kind of data
* @{
*/
/** @defgroup config_adr SW Address
* @ingroup address
* Important addresses of data stored into Config memory (and sometimes their
*dimensions)
* @{
*/
#define ADDR_CONFIG_ID 0x0010 /* /< Starting Address of the config ID
* */
#define CONFIG_ID_BYTE 2 /* /< Number of bytes of config ID */
#define ADDR_CONFIG_SENSE_LEN 0x0030 /* /< Address where is stored the number
* of sense channels */
#define ADDR_CONFIG_FORCE_LEN 0x0031 /* /< Address where is stored the number
* of force channels */
/** @}*/
/** @}*/
/** @defgroup mp_flags MP Flags value
* @ingroup mp_test
* Specify the MP flags value which are written into the flash after performing
* a full panel initialization which pass all the tests.
* @{
*/
#define MP_FLAG_FACTORY 0xA5 /* /< Full Panel Init done in factory */
#define MP_FLAG_BOOT 0x5A /* /< Full Panel Init done at boot */
#define MP_FLAG_OTHERS 0xFF /* /< Full Panel Init done somewhere
* else */
/** @}*/
/* ERROR INFO */
#define ERROR_DUMP_ROW_SIZE 32 /* /< number of rows of the error memory
* */
#define ERROR_DUMP_COL_SIZE 4 /* /< number of bytes for each row of
* the error memory */
#define ERROR_DUMP_SIGNATURE 0xFA5005AF /* /< first row signature of a
* proper dump */
/* Touch Types */
#define TOUCH_TYPE_INVALID 0x00 /* /< Invalid touch type */
#define TOUCH_TYPE_FINGER 0x01 /* /< Finger touch */
#define TOUCH_TYPE_GLOVE 0x02 /* /< Glove touch */
#define TOUCH_TYPE_STYLUS 0x03 /* /< Stylus touch */
#define TOUCH_TYPE_PALM 0x04 /* /< Palm touch */
#define TOUCH_TYPE_HOVER 0x05 /* /< Hovering touch */
/* Keys code */
#define FTS_KEY_0 0x01 /* /< Key 0 bit */
#define FTS_KEY_1 0x02 /* /< Key 1 bit */
#define FTS_KEY_2 0x04 /* /< Key 2 bit */
#define FTS_KEY_3 0x08 /* /< Key 3 bit */
#define FTS_KEY_4 0x10 /* /< Key 4 bit */
#define FTS_KEY_5 0x20 /* /< Key 5 bit */
#define FTS_KEY_6 0x40 /* /< Key 6 bit */
#define FTS_KEY_7 0x80 /* /< Key 7 bit */
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,439 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS API for MP test **
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTest.h
* \brief Contains all the definitions and structs related to the Mass
*Production Test
*/
#ifndef FTS_TEST_H
#define FTS_TEST_H
#include "ftsSoftware.h"
#ifndef LIMITS_H_FILE
/* /< Name of the Production Test Limit File */
#define LIMITS_FILE "stm_fts_production_limits.csv"
#else
#define LIMITS_FILE "NULL"
#endif
#define WAIT_FOR_FRESH_FRAMES 200 /* /< Time in ms to wait after start to
* sensing before reading a frame */
#define WAIT_AFTER_SENSEOFF 50 /* /< Time in ms to wait after stop
* sensing and before reading a frame
* from memory */
#define NO_INIT 0 /* /< No Initialization required during
* the MP */
#define RETRY_INIT_BOOT 3 /* /< number of retry of the
* initialization process at boot */
/** @defgroup mp_test Mass Production Test
* Mass production test API.
* Mass Production Test (MP) should be executed at least one time in the life
* of every device \n
* It used to verify that tit is not present any hardware damage and
* initialize some value of the chip in order to guarantee the working
* performance \n
* The MP test is made up by 3 steps:
* - ITO test = production_test_ito() \n
* - Initialization = production_test_initialization() \n
* - Data Test = production_test_data(),
* it is possible to select which items test thanks to the TestToDo struct\n
* To execute the Data Test it is mandatory load some thresholds that
* are stored in the Limit File.
* @{
*/
/** @defgroup limit_file Limit File
* @ingroup mp_test
* Production Test Limit File is a csv which contains thresholds of the data to
* test.
* This file can be loaded from the file system or stored as a header file
* according to the LIMITS_H_FILE define \n
* For each selectable test item there can be one or more associated labels
* which store the corresponding thresholds \n
* @{
*/
/* LABELS PRODUCTION TEST LIMITS FILE */
/** @defgroup test_labels Test Items Labels
* @ingroup limit_file
* Labels present in the Limit File and associated to the test items of
*TestToDo
* @{
*/
#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX"
#define MS_RAW_EACH_NODE_MIN "MS_RAW_DATA_EACH_MIN"
#define MS_RAW_EACH_NODE_MAX "MS_RAW_DATA_EACH_MAX"
#define MS_RAW_GAP "MS_RAW_DATA_GAP"
#define MS_RAW_ADJH "MS_RAW_DATA_ADJ_HORIZONTAL"
#define MS_RAW_ADJV "MS_RAW_DATA_ADJ_VERTICAL"
#define MS_RAW_ITO_ADJH "MS_RAW_ITO_DATA_ADJ_HORIZONTAL"
#define MS_RAW_ITO_ADJV "MS_RAW_ITO_DATA_ADJ_VERTICAL"
#define MS_RAW_LP_MIN_MAX "MS_RAW_LOWPOWER_DATA_MIN_MAX"
#define MS_RAW_LP_EACH_NODE_MIN "MS_RAW_LOWPOWER_DATA_EACH_MIN"
#define MS_RAW_LP_EACH_NODE_MAX "MS_RAW_LOWPOWER_DATA_EACH_MAX"
#define MS_RAW_LP_GAP "MS_RAW_LOWPOWER_DATA_GAP"
#define MS_RAW_LP_ADJH "MS_RAW_LOWPOWER_DATA_ADJ_HORIZONTAL"
#define MS_RAW_LP_ADJV "MS_RAW_LOWPOWER_DATA_ADJ_VERTICAL"
#define MS_RAW_ADJH_GAP "MS_RAW_DATA_ADJ_HORIZONTAL_P2P"
#define MS_RAW_ADJV_GAP "MS_RAW_DATA_ADJ_VERTICAL_P2P"
#define MS_RAW_ADJ_PEAK "MS_RAW_DATA_ADJ_PEAK"
#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 MS_CX1_LP_MIN_MAX "MS_TOUCH_LOWPOWER_CX1_MIN_MAX"
#define MS_CX2_LP_MAP_MIN "MS_TOUCH_LOWPOWER_CX2_MIN"
#define MS_CX2_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_MAX"
#define MS_CX2_ADJH_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_ADJ_HORIZONTAL"
#define MS_CX2_ADJV_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_ADJ_VERTICAL"
#define MS_TOTAL_CX_LP_MAP_MIN "MS_TOUCH_LOWPOWER_TOTAL_CX_MIN"
#define MS_TOTAL_CX_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_MAX"
#define MS_TOTAL_CX_ADJH_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_ADJ_HORIZONTAL"
#define MS_TOTAL_CX_ADJV_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_ADJ_VERTICAL"
#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX"
#define SS_RAW_FORCE_EACH_NODE_MIN "SS_RAW_DATA_FORCE_EACH_MIN"
#define SS_RAW_FORCE_EACH_NODE_MAX "SS_RAW_DATA_FORCE_EACH_MAX"
#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX"
#define SS_RAW_SENSE_EACH_NODE_MIN "SS_RAW_DATA_SENSE_EACH_MIN"
#define SS_RAW_SENSE_EACH_NODE_MAX "SS_RAW_DATA_SENSE_EACH_MAX"
#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP"
#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP"
#define SS_RAW_LP_FORCE_MIN_MAX "SS_RAW_LOWPOWER_DATA_FORCE_MIN_MAX"
#define SS_RAW_LP_SENSE_MIN_MAX "SS_RAW_LOWPOWER_DATA_SENSE_MIN_MAX"
#define SS_RAW_LP_FORCE_EACH_NODE_MIN "SS_RAW_LOWPOWER_DATA_FORCE_EACH_MIN"
#define SS_RAW_LP_FORCE_EACH_NODE_MAX "SS_RAW_LOWPOWER_DATA_FORCE_EACH_MAX"
#define SS_RAW_LP_SENSE_MIN_MAX "SS_RAW_LOWPOWER_DATA_SENSE_MIN_MAX"
#define SS_RAW_LP_SENSE_EACH_NODE_MIN "SS_RAW_LOWPOWER_DATA_SENSE_EACH_MIN"
#define SS_RAW_LP_SENSE_EACH_NODE_MAX "SS_RAW_LOWPOWER_DATA_SENSE_EACH_MAX"
#define SS_RAW_LP_FORCE_GAP "SS_RAW_LOWPOWER_DATA_FORCE_GAP"
#define SS_RAW_LP_SENSE_GAP "SS_RAW_LOWPOWER_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"
/* Idle (LP) version*/
#define SS_IX1_LP_FORCE_MIN_MAX "SS_TOUCH_IDLE_IX1_FORCE_MIN_MAX"
#define SS_IX1_LP_SENSE_MIN_MAX "SS_TOUCH_IDLE_IX1_SENSE_MIN_MAX"
#define SS_CX1_LP_FORCE_MIN_MAX "SS_TOUCH_IDLE_CX1_FORCE_MIN_MAX"
#define SS_CX1_LP_SENSE_MIN_MAX "SS_TOUCH_IDLE_CX1_SENSE_MIN_MAX"
#define SS_IX2_LP_FORCE_MAP_MIN "SS_TOUCH_IDLE_IX2_FORCE_MIN"
#define SS_IX2_LP_FORCE_MAP_MAX "SS_TOUCH_IDLE_IX2_FORCE_MAX"
#define SS_IX2_LP_SENSE_MAP_MIN "SS_TOUCH_IDLE_IX2_SENSE_MIN"
#define SS_IX2_LP_SENSE_MAP_MAX "SS_TOUCH_IDLE_IX2_SENSE_MAX"
#define SS_IX2_LP_FORCE_ADJV_MAP_MAX "SS_TOUCH_IDLE_IX2_ADJ_VERTICAL"
#define SS_IX2_LP_SENSE_ADJH_MAP_MAX "SS_TOUCH_IDLE_IX2_ADJ_HORIZONTAL"
#define SS_CX2_LP_FORCE_MAP_MIN "SS_TOUCH_IDLE_CX2_FORCE_MIN"
#define SS_CX2_LP_FORCE_MAP_MAX "SS_TOUCH_IDLE_CX2_FORCE_MAX"
#define SS_CX2_LP_SENSE_MAP_MIN "SS_TOUCH_IDLE_CX2_SENSE_MIN"
#define SS_CX2_LP_SENSE_MAP_MAX "SS_TOUCH_IDLE_CX2_SENSE_MAX"
#define SS_CX2_LP_FORCE_ADJV_MAP_MAX "SS_TOUCH_IDLE_CX2_ADJ_VERTICAL"
#define SS_CX2_LP_SENSE_ADJH_MAP_MAX "SS_TOUCH_IDLE_CX2_ADJ_HORIZONTAL"
/* TOTAL SS */
#define SS_TOTAL_IX_LP_FORCE_MAP_MIN "SS_TOUCH_IDLE_TOTAL_IX_FORCE_MIN"
#define SS_TOTAL_IX_LP_FORCE_MAP_MAX "SS_TOUCH_IDLE_TOTAL_IX_FORCE_MAX"
#define SS_TOTAL_IX_LP_SENSE_MAP_MIN "SS_TOUCH_IDLE_TOTAL_IX_SENSE_MIN"
#define SS_TOTAL_IX_LP_SENSE_MAP_MAX "SS_TOUCH_IDLE_TOTAL_IX_SENSE_MAX"
#define SS_TOTAL_IX_LP_FORCE_ADJV_MAP_MAX \
"SS_TOUCH_IDLE_TOTAL_IX_ADJ_VERTICAL"
#define SS_TOTAL_IX_LP_SENSE_ADJH_MAP_MAX \
"SS_TOUCH_IDLE_TOTAL_IX_ADJ_HORIZONTAL"
#define SS_TOTAL_CX_LP_FORCE_MAP_MIN "SS_TOUCH_IDLE_TOTAL_CX_FORCE_MIN"
#define SS_TOTAL_CX_LP_FORCE_MAP_MAX "SS_TOUCH_IDLE_TOTAL_CX_FORCE_MAX"
#define SS_TOTAL_CX_LP_SENSE_MAP_MIN "SS_TOUCH_IDLE_TOTAL_CX_SENSE_MIN"
#define SS_TOTAL_CX_LP_SENSE_MAP_MAX "SS_TOUCH_IDLE_TOTAL_CX_SENSE_MAX"
#define SS_TOTAL_CX_LP_FORCE_ADJV_MAP_MAX \
"SS_TOUCH_IDLE_TOTAL_CX_ADJ_VERTICAL"
#define SS_TOTAL_CX_LP_SENSE_ADJH_MAP_MAX \
"SS_TOUCH_IDLE_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"
/** @}*/
/**
* Struct used to specify which test perform during the Mass Production Test.
* For each test item selected in this structure, there should be one or
* more labels associated in the Limit file from where load the thresholds
*/
typedef struct {
int MutualRaw; /* /< MS Raw min/Max test */
int MutualRawMap; /* /< MS Raw min/Max test for each node */
int MutualRawGap; /* /< MS Raw Gap(max-min) test */
int MutualRawAdj; /* /< MS Raw Adjacent test */
int MutualRawAdjGap; /* /< MS Raw Adjacent Gap (max-min) test */
int MutualRawAdjPeak; /* /< MS Raw Adjacent Peak
* max(max(adjv),max(adjh)) test */
int MutualRawLP; /* /< MS Low Power Raw min/Max test */
int MutualRawMapLP; /* /< MS Low Power Raw min/Max test
* for each node */
int MutualRawGapLP; /* /< MS Low Power Raw Gap(max-min) test */
int MutualRawAdjLP; /* /< MS Low Power Raw Adjacent test */
int MutualRawAdjITO; /* /< MS Raw Adjacent test during ITO test */
int MutualCx1; /* /< MS Cx1 min/Max test */
int MutualCx2; /* /< MS Cx2 min/Max (for each node) test */
int MutualCx2Adj; /* /< MS Vertical and Horizontal Adj Cx2 min/Max
* (for each node) test */
int MutualCxTotal; /* /< MS Total Cx min/Max (for each node) test
* */
int MutualCxTotalAdj; /* /< MS Total vertical and Horizontal Adj Cx2
* min/Max (for each node) test */
int MutualCx1LP; /* /< MS LowPower Cx1 min/Max test */
int MutualCx2LP; /* /< MS LowPower Cx2 min/Max (for each node) test */
int MutualCx2AdjLP; /* /< MS LowPower Vertical and Horizontal Adj Cx2 min/Max
* (for each node) test */
int MutualCxTotalLP; /* /< MS Total LowPower Cx min/Max (for each node) test
* */
int MutualCxTotalAdjLP; /* /< MS Total LowPower vertical and Horizontal Adj Cx2
* min/Max (for each node) test */
int MutualKeyRaw; /* /< MS Raw Key min/Max test */
int MutualKeyCx1; /* /< MS Cx1 Key min/Max test */
int MutualKeyCx2; /* /< MS Cx2 Key min/Max (for each node) test */
int MutualKeyCxTotal; /* /< MS Total Cx Key min/Max (for each node)
* test */
int SelfForceRaw; /* /< SS Force Raw min/Max test */
int SelfForceRawGap; /* /< SS Force Raw Gap(max-min) test */
int SelfForceRawMap; /* /< SS Force Raw min/Max Map test */
int SelfForceRawLP; /* /< SS Low Power Force Raw min/Max test */
int SelfForceRawGapLP; /* /< SS Low Power Force Raw Gap(max-min)test */
int SelfForceRawMapLP; /* /< SS Low Power Force Raw min/Max Map test */
int SelfForceIx1; /* /< SS Force Ix1 min/Max test */
int SelfForceIx2; /* /< SS Force Ix2 min/Max (for each node) test
* */
int SelfForceIx2Adj; /* /< SS Vertical Adj Force Ix2 min/Max
* (for each node) test */
int SelfForceIxTotal; /* /< SS Total Force Ix min/Max (for each node)
* test */
int SelfForceIxTotalAdj; /* /< SS Total Vertical Adj Force Ix
* min/Max (for each node) test */
int SelfForceCx1; /* /< SS Force Cx1 min/Max test */
int SelfForceCx2; /* /< SS Force Cx2 min/Max (for each node) test */
int SelfForceCx2Adj; /* /< SS Vertical Adj Force Cx2 min/Max (for
* each node) test */
int SelfForceCxTotal; /* /< SS Total Force Cx min/Max (for each node)
* test */
int SelfForceCxTotalAdj; /* /< SS Total Vertical Adj Force Cx
* min/Max (for each node) test */
int SelfForceIx1LP; /* /< SS LP Force Ix1 min/Max test */
int SelfForceIx2LP; /* /< SS LP Force Ix2 min/Max (for each node)
* test */
int SelfForceIx2AdjLP; /* /< SS LP Vertical Adj Force Ix2 min/Max
* (for each node) test */
int SelfForceIxTotalLP; /* /< SS LP Total Force Ix min/Max
* (for each node) test */
int SelfForceIxTotalAdjLP; /* /< SS LP Total Vertical Adj Force Ix
* min/Max (for each node) test */
int SelfForceCx1LP; /* /< SS LP Force Cx1 min/Max test */
int SelfForceCx2LP; /* /< SS LP Force Cx2 min/Max (for each node) test */
int SelfForceCx2AdjLP; /* /< SS LP Vertical Adj Force Cx2 min/Max (for
* each node) test */
int SelfForceCxTotalLP; /* /< SS LP Total Force Cx min/Max
* (for each node) test */
int SelfForceCxTotalAdjLP; /* /< SS LP Total Vertical Adj Force Cx
* min/Max (for each node) test */
int SelfSenseRaw; /* /< SS Sense Raw min/Max test */
int SelfSenseRawGap; /* /< SS Sense Raw Gap(max-min) test */
int SelfSenseRawMap; /* /< SS Sense Raw min/Max test for each node */
int SelfSenseRawLP; /* /< SS Low Power Sense Raw min/Max test */
int SelfSenseRawGapLP; /* /< SS Low Power Sense Raw Gap(max-min) test */
int SelfSenseRawMapLP; /* /< SS Low Power Sense Raw min/Max test for
* each node */
int SelfSenseIx1; /* /< SS Sense Ix1 min/Max test */
int SelfSenseIx2; /* /< SS Sense Ix2 min/Max (for each node) test */
int SelfSenseIx2Adj; /* /< SS Horizontal Adj Sense Ix2 min/Max
* (for each node) test */
int SelfSenseIxTotal; /* /< SS Total Horizontal Sense Ix min/Max
* (for each node) test */
int SelfSenseIxTotalAdj; /* /< SS Total Horizontal Adj Sense Ix
* min/Max (for each node) test */
int SelfSenseCx1; /* /< SS Sense Cx1 min/Max test */
int SelfSenseCx2; /* /< SS Sense Cx2 min/Max (for each node) test */
int SelfSenseCx2Adj; /* /< SS Horizontal Adj Sense Cx2 min/Max
* (for each node) test */
int SelfSenseCxTotal; /* /< SS Total Sense Cx min/Max (for each node)
* test */
int SelfSenseCxTotalAdj; /* /< SS Total Horizontal Adj Sense Cx
* min/Max (for each node) test */
int SelfSenseIx1LP; /* /< SS LP Sense Ix1 min/Max test */
int SelfSenseIx2LP; /* /< SS LP Sense Ix2 min/Max (for each node)
* test */
int SelfSenseIx2AdjLP; /* /< SS LP Horizontal Adj Sense Ix2 min/Max
* (for each node) test */
int SelfSenseIxTotalLP; /* /< SS LP Total Horizontal Sense Ix min/Max
* (for each node) test */
int SelfSenseIxTotalAdjLP; /* /< SS LP Total Horizontal Adj Sense Ix
* min/Max (for each node) test */
int SelfSenseCx1LP; /* /< SS LP Sense Cx1 min/Max test */
int SelfSenseCx2LP; /* /< SS LP Sense Cx2 min/Max (for each node)
* test */
int SelfSenseCx2AdjLP; /* /< SS LP Horizontal Adj Sense Cx2 min/Max
* (for each node) test */
int SelfSenseCxTotalLP; /* /< SS LP Total Sense Cx min/Max
* (for each node) test */
int SelfSenseCxTotalAdjLP; /* /< SS LP Total Horizontal Adj Sense Cx
* min/Max (for each node) test */
} TestToDo;
#define MAX_LIMIT_FILE_NAME 100 /* /< max number of chars of the limit file name
* */
/**
* Struct which store the data coming from a Production Limit File
*/
typedef struct {
char *data; /* /< pointer to an array of char which contains
* the content of the Production Limit File */
int size; /* /< size of data */
char name[MAX_LIMIT_FILE_NAME]; /* /< identifier of the source from
* where the limits data were loaded (if
* loaded from a file it will be the
* file name, while if loaded from .h
* will be "NULL") */
} LimitFile;
int initTestToDo(void);
/**@}*/
/**@}*/
int computeAdjHoriz(i8 *data, int row, int column, u8 **result);
int computeAdjHorizTotal(short *data, int row, int column, u16 **result);
int computeAdjVert(i8 *data, int row, int column, u8 **result);
int computeAdjVertTotal(short *data, int row, int column, u16 **result);
int computeAdjHorizFromU(u8 *data, int row, int column, u8 **result);
int computeAdjHorizTotalFromU(u16 *data, int row, int column, u16 **result);
int computeAdjVertFromU(u8 *data, int row, int column, u8 **result);
int computeAdjVertTotalFromU(u16 *data, int row, int column, u16 **result);
int checkLimitsMinMax(short *data, int row, int column, int min, int max);
int checkLimitsMap(i8 *data, int row, int column, int *min, int *max);
int checkLimitsMapTotal(short *data, int row, int column, int *min, int *max);
int checkLimitsMapFromU(u8 *data, int row, int column, int *min, int *max);
int checkLimitsMapTotalFromU(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 checkLimitsGap(short *data, int row, int column, int threshold);
int checkLimitsGapOffsets(short *data, int row, int column, int threshold,
int row_start, int column_start, int row_end, int column_end);
/** @defgroup mp_api MP API
* @ingroup mp_test
* Functions to execute the MP test.
* The parameters of these functions allow to customize their behavior
* in order to satisfy different scenarios
* @{
*/
int production_test_ito(char *path_limits, TestToDo *todo);
int production_test_initialization(u8 type);
int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit,
TestToDo *todo, u8 mpflag);
int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
int production_test_ms_raw_lp(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo);
int production_test_ms_cx_lp(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo);
int production_test_ss_raw_lp(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_ss_ix_cx(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_ss_ix_cx_lp(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo);
int production_test_ms_key_cx(char *path_limits, int stop_on_fail,
TestToDo *todo);
int production_test_ms_key_raw(char *path_limits);
/** @}*/
/**
* @addtogroup limit_file
* @{
*/
int parseProductionTestLimits(char *path, LimitFile *file, char *label,
int **data, int *row, int *column);
int readLine(char *data, char *line, int size, int *n);
int getLimitsFile(char *path, LimitFile *file);
int freeLimitsFile(LimitFile *file);
int freeCurrentLimitsFile(void);
/**@}*/
#endif

View file

@ -0,0 +1,85 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility for mesuring/handling the time *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTime.c
* \brief Contains all functions to handle and measure the time in the driver
*/
#include "ftsTime.h"
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/ctype.h>
/**
* Take the starting time and save it in a StopWatch variable
* @param w pointer of a StopWatch struct
*/
void startStopWatch(StopWatch *w)
{
w->start = current_kernel_time();
}
/**
* Take the stop time and save it in a StopWatch variable
* @param w pointer of a StopWatch struct
*/
void stopStopWatch(StopWatch *w)
{
w->end = current_kernel_time();
}
/**
* Compute the amount of time spent from when the startStopWatch and then
* the stopStopWatch were called on the StopWatch variable
* @param w pointer of a StopWatch struct
* @return amount of time in ms (the return value is meaningless
* if the startStopWatch and stopStopWatch were not called before)
*/
int elapsedMillisecond(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;
}
/**
* Compute the amount of time spent from when the startStopWatch and
* then the stopStopWatch were called on the StopWatch variable
* @param w pointer of a StopWatch struct
* @return amount of time in ns (the return value is meaningless
* if the startStopWatch and stopStopWatch were not called before)
*/
int elapsedNanosecond(StopWatch *w)
{
int result;
result = ((w->end.tv_sec - w->start.tv_sec) * 1000000000) +
(w->end.tv_nsec - w->start.tv_nsec);
return result;
}

View file

@ -0,0 +1,73 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility for measuring/handling the time *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTime.h
* \brief Contains all the definitions and structs to handle and measure the
* time in the driver
*/
#ifndef FTS_TIME_H
#define FTS_TIME_H
#include <linux/time.h>
/* TIMEOUT */
/** @defgroup timeouts Timeouts
* Definitions of all the Timeout used in several operations
* @{
*/
#define TIMEOUT_RESOLUTION 50
/* /< timeout resolution in ms (all timeout should be multiples of this unit) */
#define GENERAL_TIMEOUT (15 * TIMEOUT_RESOLUTION)
/* /< general timeout in ms */
#define RELEASE_INFO_TIMEOUT (2 * TIMEOUT_RESOLUTION)
/* /< timeout to request release info in ms */
#define TIMEOUT_REQU_COMP_DATA (4 * TIMEOUT_RESOLUTION)
/* /< timeout to request compensation data in ms */
#define TIMEOUT_REQU_DATA (8 * TIMEOUT_RESOLUTION)
/* /< timeout to request data in ms */
#define TIMEOUT_ITO_TEST_RESULT (4 * TIMEOUT_RESOLUTION)
/* /< timeout to perform ito test in ms */
#define TIMEOUT_INITIALIZATION_TEST_RESULT (5000 * TIMEOUT_RESOLUTION)
/* /< timeout to perform initialization test in ms */
#define TIEMOUT_ECHO (50 * TIMEOUT_RESOLUTION)
/* /< timeout of the echo command,*/
#define TIMEOUT_ECHO_FPI (200 * TIMEOUT_RESOLUTION)
/* /< timeout of the Full panel Init echo command */
#define TIMEOUT_ECHO_SINGLE_ENDED_SPECIAL_AUTOTUNE \
(100 * TIMEOUT_RESOLUTION)
/* /< timeout of the Single ended special Autotune echo command */
/** @}*/
/**
* Struct used to measure the time elapsed between a starting and ending point.
*/
typedef struct {
struct timespec start; /* /< store the starting time */
struct timespec end; /* /< store the finishing time */
} StopWatch;
void startStopWatch(StopWatch *w);
void stopStopWatch(StopWatch *w);
int elapsedMillisecond(StopWatch *w);
int elapsedNanosecond(StopWatch *w);
#endif

View file

@ -0,0 +1,715 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility Functions *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTool.c
* \brief Contains all the functions to support common operation inside the
*driver
*/
#include "ftsCompensation.h"
#include "ftsCore.h"
#include "ftsError.h"
#include "ftsHardware.h"
#include "ftsIO.h"
#include "ftsSoftware.h"
#include "ftsTime.h"
#include "ftsTool.h"
#include "../fts.h" /* needed for the tag define */
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <stdarg.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ctype.h>
/**
* Print an array of byte in a HEX string and attach at the beginning a label.
* The function allocate memory that should be free outside the function itself
* @param label string to attach at the beginning
* @param buff pointer to the byte array that should be printed as HEX string
* @param count size of buff
* @param result pointer to the array of characters that compose the HEX final
* string
* @return pointer to the array of characters that compose the HEX string,
* (same address of result)
* @warning result MUST be allocated outside the function and should be
* big enough to contain the data converted as HEX!
*/
char *printHex(char *label, u8 *buff, int count, u8 *result)
{
int i, offset;
offset = strlen(label);
strlcpy(result, label, offset+1); /* +1 for terminator char */
for (i = 0; i < count; i++) {
snprintf(&result[offset], 4, "%02X ", buff[i]);
/* this append automatically a null terminator char */
offset += 3;
}
return result;
}
/**
* Clear the FIFO from any event
* @return OK if success or an error code which specify the type of error
*/
int flushFIFO(void)
{
int ret;
u8 sett = SPECIAL_FIFO_FLUSH;
ret = writeSysCmd(SYS_CMD_SPECIAL, &sett, 1); /* flush the FIFO */
if (ret < OK) {
logError(1, "%s flushFIFO: ERROR %08X\n", tag, ret);
return ret;
}
logError(0, "%s FIFO flushed!\n", tag);
return OK;
}
/**
* Convert an array of bytes to an array of u16 taking two bytes at time,
* src has LSB first.
* @param src pointer to the source byte array
* @param src_length size of src
* @param dst pointer to the destination array.
* @return the final size of dst (half of the source) or ERROR_OP_NOT_ALLOW
* if the size of src is not multiple of 2.
*/
int u8ToU16n(u8 *src, int src_length, u16 *dst)
{
int i, j;
if (src_length % 2 != 0)
return ERROR_OP_NOT_ALLOW;
else {
j = 0;
dst = (u16 *)kmalloc((src_length / 2) * sizeof(u16),
GFP_KERNEL);
for (i = 0; i < src_length; i += 2) {
dst[j] = ((src[i + 1] & 0x00FF) << 8) + (src[i] &
0x00FF);
j++;
}
}
return src_length / 2;
}
/**
* Convert an array of 2 bytes to a u16, src has LSB first (little endian).
* @param src pointer to the source byte array
* @param dst pointer to the destination u16.
* @return OK
*/
int u8ToU16(u8 *src, u16 *dst)
{
*dst = (u16)(((src[1] & 0x00FF) << 8) + (src[0] & 0x00FF));
return OK;
}
/**
* Convert an array of 2 bytes to a u16, src has MSB first (big endian).
* @param src pointer to the source byte array
* @param dst pointer to the destination u16.
* @return OK
*/
int u8ToU16_be(u8 *src, u16 *dst)
{
*dst = (u16)(((src[0] & 0x00FF) << 8) + (src[1] & 0x00FF));
return OK;
}
/**
* Convert an array of u16 to an array of u8, dst has MSB first (big endian).
* @param src pointer to the source array of u16
* @param src_length size of src
* @param dst pointer to the destination array of u8. This array should be free
* when no need anymore
* @return size of dst (src size multiply by 2)
*/
int u16ToU8n_be(u16 *src, int src_length, u8 *dst)
{
int i, j;
dst = (u8 *)kmalloc((2 * src_length) * sizeof(u8), GFP_KERNEL);
j = 0;
for (i = 0; i < src_length; i++) {
dst[j] = (u8)(src[i] & 0xFF00) >> 8;
dst[j + 1] = (u8)(src[i] & 0x00FF);
j += 2;
}
return src_length * 2;
}
/**
* Convert a u16 to an array of 2 u8, dst has MSB first (big endian).
* @param src u16 to convert
* @param dst pointer to the destination array of 2 u8.
* @return OK
*/
int u16ToU8_be(u16 src, u8 *dst)
{
dst[0] = (u8)((src & 0xFF00) >> 8);
dst[1] = (u8)(src & 0x00FF);
return OK;
}
/**
* Convert a u16 to an array of 2 u8, dst has LSB first (little endian).
* @param src u16 to convert
* @param dst pointer to the destination array of 2 u8.
* @return OK
*/
int u16ToU8(u16 src, u8 *dst)
{
dst[1] = (u8)((src & 0xFF00) >> 8);
dst[0] = (u8)(src & 0x00FF);
return OK;
}
/**
* Convert an array of bytes to a u32, src has LSB first (little endian).
* @param src array of bytes to convert
* @param dst pointer to the destination u32 variable.
* @return OK
*/
int u8ToU32(u8 *src, u32 *dst)
{
*dst = (u32)(((src[3] & 0xFF) << 24) + ((src[2] & 0xFF) << 16) +
((src[1] & 0xFF) << 8) + (src[0] & 0xFF));
return OK;
}
/**
* Convert an array of bytes to a u32, src has MSB first (big endian).
* @param src array of bytes to convert
* @param dst pointer to the destination u32 variable.
* @return OK
*/
int u8ToU32_be(u8 *src, u32 *dst)
{
*dst = (u32)(((src[0] & 0xFF) << 24) + ((src[1] & 0xFF) << 16) +
((src[2] & 0xFF) << 8) + (src[3] & 0xFF));
return OK;
}
/**
* Convert a u32 to an array of 4 bytes, dst has LSB first (little endian).
* @param src u32 value to convert
* @param dst pointer to the destination array of 4 bytes.
* @return OK
*/
int u32ToU8(u32 src, u8 *dst)
{
dst[3] = (u8)((src & 0xFF000000) >> 24);
dst[2] = (u8)((src & 0x00FF0000) >> 16);
dst[1] = (u8)((src & 0x0000FF00) >> 8);
dst[0] = (u8)(src & 0x000000FF);
return OK;
}
/**
* Convert a u32 to an array of 4 bytes, dst has MSB first (big endian).
* @param src u32 value to convert
* @param dst pointer to the destination array of 4 bytes.
* @return OK
*/
int u32ToU8_be(u32 src, u8 *dst)
{
dst[0] = (u8)((src & 0xFF000000) >> 24);
dst[1] = (u8)((src & 0x00FF0000) >> 16);
dst[2] = (u8)((src & 0x0000FF00) >> 8);
dst[3] = (u8)(src & 0x000000FF);
return OK;
}
/**
* Execute a function passed as argment and retry it defined number of times if
*not successfull
* @param code pointer to a function which return an int and doesn't have any
*parameters
* @param wait_before_retry interval of time in ms to wait between one trial
*and another one
* @param retry_count max number of retry to attemp
* @return last return value obtained from the last execution of the code
*function
*/
int attempt_function(int (*code)(void), unsigned long wait_before_retry, int
retry_count)
{
int result;
int count = 0;
do {
result = code();
count++;
msleep(wait_before_retry);
} while (count < retry_count && result < 0);
if (count == retry_count)
return result | ERROR_TIMEOUT;
else
return result;
}
/**
* Enable all the possible sensing mode supported by the FW
* @return OK if success or an error code which specify the type of error
*/
int senseOn(void)
{
int ret;
ret = setScanMode(SCAN_MODE_ACTIVE, 0xFF); /* enable all */
if (ret < OK) {
logError(1, "%s senseOn: ERROR %08X\n", tag, ret);
return ret;
}
logError(0, "%s senseOn: SENSE ON\n", tag);
return OK;
}
/**
* Disable all the sensing mode
* @return OK if success or an error code which specify the type of error
*/
int senseOff(void)
{
int ret;
ret = setScanMode(SCAN_MODE_ACTIVE, 0x00);
if (ret < OK) {
logError(1, "%s senseOff: ERROR %08X\n", tag, ret);
return ret;
}
logError(0, "%s senseOff: SENSE OFF\n", tag);
return OK;
}
/**
* Clean up the IC status executing a system reset and giving
* the possibility to re-enabling the sensing
* @param enableTouch if 1, re-enable the sensing and the interrupt of the IC
* @return OK if success or an error code which specify the type of error
*/
int cleanUp(int enableTouch)
{
int res;
logError(0, "%s cleanUp: system reset...\n", tag);
res = fts_system_reset();
if (res < OK)
return res;
if (enableTouch) {
logError(0, "%s cleanUp: enabling touches...\n", tag);
res = senseOn(); /* already enable everything */
if (res < OK)
return res;
logError(0, "%s cleanUp: enabling interrupts...\n", tag);
res = fts_enableInterrupt();
if (res < OK)
return res;
}
return OK;
}
/**
* Transform an array of short in a matrix of short with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
short **array1dTo2d_short(short *data, int size, int columns)
{
int i;
short **matrix = NULL;
if (size == 0) {
matrix = (short **)kmalloc(1 *
sizeof(short *), GFP_KERNEL);
matrix[0] = (short *)kmalloc(0 *
sizeof(short), GFP_KERNEL);
} else {
matrix = (short **)kmalloc(((int)(size / columns)) *
sizeof(short *), GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (short *)kmalloc(columns *
sizeof(short), GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Transform an array of u16 in a matrix of u16 with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of u16 where for each row there are columns
* elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
u16 **array1dTo2d_u16(u16 *data, int size, int columns)
{
int i;
u16 **matrix = NULL;
if (size == 0) {
matrix = (u16 **)kmalloc(1 *
sizeof(u16 *), GFP_KERNEL);
matrix[0] = (u16 *)kmalloc(0 *
sizeof(u16), GFP_KERNEL);
} else {
matrix = (u16 **)kmalloc(((int)(size / columns)) *
sizeof(u16 *), GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (u16 *)kmalloc(columns *
sizeof(u16), GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Transform an array of u8 in a matrix of u8 with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
u8 **array1dTo2d_u8(u8 *data, int size, int columns)
{
int i;
u8 **matrix = NULL;
if (size == 0) {
matrix = (u8 **)kmalloc(1 *
sizeof(u8 *), GFP_KERNEL);
matrix[0] = (u8 *)kmalloc(0 *
sizeof(u8), GFP_KERNEL);
} else {
matrix = (u8 **)kmalloc(((int)(size / columns)) * sizeof(u8 *),
GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (u8 *)kmalloc(columns * sizeof(u8),
GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Transform an array of i8 in a matrix of i8 with a defined number of
* columns and the resulting number of rows
* @param data array of bytes to convert
* @param size size of data
* @param columns number of columns that the resulting matrix should have.
* @return a reference to a matrix of short where for each row there are
* columns elements
* @warning If size = 0 it will be allocated a matrix 1*1 wich still should
* be free
*/
i8 **array1dTo2d_i8(i8 *data, int size, int columns)
{
int i;
i8 **matrix = NULL;
if (size == 0) {
matrix = (i8 **)kmalloc(1 *
sizeof(i8 *), GFP_KERNEL);
matrix[0] = (i8 *)kmalloc(0 *
sizeof(i8), GFP_KERNEL);
} else {
matrix = (i8 **)kmalloc(((int)(size / columns)) * sizeof(i8 *),
GFP_KERNEL);
if (matrix != NULL) {
for (i = 0; i < (int)(size / columns); i++)
matrix[i] = (i8 *)kmalloc(columns * sizeof(i8),
GFP_KERNEL);
for (i = 0; i < size; i++)
matrix[i / columns][i % columns] = data[i];
}
}
return matrix;
}
/**
* Print in the kernel log a label followed by a matrix of short row x columns
*and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of short which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_short(char *label, short **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Print in the kernel log a label followed by a matrix of u16 row x columns
*and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u16 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_u16(char *label, u16 **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Print in the kernel log a label followed by a matrix of u8 row x columns and
*free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u8 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_u8(char *label, u8 **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Print in the kernel log a label followed by a matrix of i8 row x columns and
* free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u8 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_i8(char *label, i8 **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Print in the kernel log a label followed by a matrix of u32 row x columns
*and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of u32 which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_u32(char *label, u32 **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Print in the kernel log a label followed by a matrix of int row x columns
* and free its memory
* @param label pointer to the string to print before the actual matrix
* @param matrix reference to the matrix of int which contain the actual data
* @param row number of rows on which the matrix should be print
* @param column number of columns for each row
*/
void print_frame_int(char *label, int **matrix, int row, int column)
{
int i, j;
logError(0, "%s %s\n", tag, label);
for (i = 0; i < row; i++) {
logError(0, "%s ", tag);
for (j = 0; j < column; j++)
printk("%d ", matrix[i][j]);
logError(0, "\n");
kfree(matrix[i]);
}
kfree(matrix);
}
/**
* Convert an array of bytes to an u64, src has MSB first (big endian).
* @param src array of bytes
* @param dest pointer to the destination u64.
* @param size size of src (can be <= 8)
* @return OK if success or ERROR_OP_NOT_ALLOW if size exceed 8
*/
int u8ToU64_be(u8 *src, u64 *dest, int size)
{
int i = 0;
/* u64 temp =0; */
if (size > sizeof(u64))
return ERROR_OP_NOT_ALLOW;
else {
*dest = 0;
for (i = 0; i < size; i++)
*dest |= (u64)(src[i]) << ((size - 1 - i) * 8);
return OK;
}
}
/**
* Convert an u64 to an array of bytes, dest has MSB first (big endian).
* @param src value of u64
* @param dest pointer to the destination array of bytes.
* @param size size of src (can be <= 8)
* @return OK if success or ERROR_OP_NOT_ALLOW if size exceed 8
*/
int u64ToU8_be(u64 src, u8 *dest, int size)
{
int i = 0;
if (size > sizeof(u64))
return ERROR_OP_NOT_ALLOW;
else
for (i = 0; i < size; i++)
dest[i] = (u8)((src >> ((size - 1 - i) * 8)) & 0xFF);
return OK;
}
/*********** NEW API *************/
/**
* Convert a value of an id in a bitmask with a 1 in the position of the value
*of the id
* @param id Value of the ID to convert
* @param mask pointer to the bitmask that will be updated with the value of id
* @param size dimension in bytes of mask
* @return OK if success or ERROR_OP_NOT_ALLOW if size of mask is not enough to
*contain ID
*/
int fromIDtoMask(u8 id, u8 *mask, int size)
{
if (((int)((id) / 8)) < size) {
logError(0, "%s %s: ID = %d Index = %d Position = %d !\n", tag,
__func__, id, ((int)((id) / 8)), (id % 8));
mask[((int)((id) / 8))] |= 0x01 << (id % 8);
return OK;
} else {
logError(1,
"%s %s: Bitmask too small! Impossible contain ID = %d %d>=%d! ERROR %08X\n",
tag, __func__, id, ((int)((id) / 8)), size,
ERROR_OP_NOT_ALLOW);
return ERROR_OP_NOT_ALLOW;
}
}

View file

@ -0,0 +1,59 @@
/*
*
**************************************************************************
** STMicroelectronics **
**************************************************************************
** marco.cali@st.com **
**************************************************************************
* *
* FTS Utility Functions *
* *
**************************************************************************
**************************************************************************
*
*/
/*!
* \file ftsTool.h
* \brief Contains all the definitions to support common operations inside the
* driver
*/
#ifndef FTS_TOOL_H
#define FTS_TOOL_H
char *printHex(char *label, u8 *buff, int count, u8 *result);
int u8ToU16(u8 *src, u16 *dst);
int u8ToU16_be(u8 *src, u16 *dst);
int u8ToU16n(u8 *src, int src_length, u16 *dst);
int u16ToU8(u16 src, u8 *dst);
int u16ToU8_be(u16 src, u8 *dst);
int u16ToU8n_be(u16 *src, int src_length, u8 *dst);
int u8ToU32(u8 *src, u32 *dst);
int u8ToU32_be(u8 *src, u32 *dst);
int u32ToU8(u32 src, u8 *dst);
int u32ToU8_be(u32 src, u8 *dst);
int u8ToU64_be(u8 *src, u64 *dest, int size);
int u64ToU8_be(u64 src, u8 *dest, int size);
int attempt_function(int (*code)(void), unsigned long wait_before_retry, int
retry_count);
int senseOn(void);
int senseOff(void);
void print_frame_short(char *label, short **matrix, int row, int column);
short **array1dTo2d_short(short *data, int size, int columns);
void print_frame_u16(char *label, u16 **matrix, int row, int column);
u16 **array1dTo2d_u16(u16 *data, int size, int columns);
u8 **array1dTo2d_u8(u8 *data, int size, int columns);
i8 **array1dTo2d_i8(i8 *data, int size, int columns);
void print_frame_u8(char *label, u8 **matrix, int row, int column);
void print_frame_i8(char *label, i8 **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);
/* New API */
int fromIDtoMask(u8 id, u8 *mask, int size);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff