touch: add drivers

Add all drivers for new platforms.

Change-Id: Ie9947b0c6f8ddfee7dab6dfa80d6aca62323f4da
Signed-off-by: Fei Mao <feim1@codeaurora.org>
This commit is contained in:
Fei Mao
2021-10-19 19:03:59 +08:00
parent 7bcfa88cc1
commit cb9d543e8a
62 changed files with 64222 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2012-2019, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_common.h
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-16
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
#ifndef __LINUX_FOCALTECH_COMMON_H__
#define __LINUX_FOCALTECH_COMMON_H__
#include "focaltech_config.h"
/*****************************************************************************
* Macro definitions using #define
*****************************************************************************/
#define FTS_DRIVER_VERSION "Focaltech V3.2 20200422"
#define BYTE_OFF_0(x) (u8)((x) & 0xFF)
#define BYTE_OFF_8(x) (u8)(((x) >> 8) & 0xFF)
#define BYTE_OFF_16(x) (u8)(((x) >> 16) & 0xFF)
#define BYTE_OFF_24(x) (u8)(((x) >> 24) & 0xFF)
#define FLAGBIT(x) (0x00000001 << (x))
#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) & (0xFFFFFFFF << (x)))
#define FLAG_ICSERIALS_LEN 8
#define FLAG_HID_BIT 10
#define FLAG_IDC_BIT 11
#define IC_SERIALS(type) ((type) & FLAGBITS(0, FLAG_ICSERIALS_LEN-1))
#define IC_TO_SERIALS(x) ((x) & FLAGBITS(0, FLAG_ICSERIALS_LEN-1))
#define FTS_CHIP_IDC(type) (((type) & FLAGBIT(FLAG_IDC_BIT)) == FLAGBIT(FLAG_IDC_BIT))
#define FTS_HID_SUPPORTTED(type) (((type) & FLAGBIT(FLAG_HID_BIT)) == FLAGBIT(FLAG_HID_BIT))
#define FILE_NAME_LENGTH 128
#define ENABLE 1
#define DISABLE 0
#define VALID 1
#define INVALID 0
#define FTS_CMD_START1 0x55
#define FTS_CMD_START2 0xAA
#define FTS_CMD_START_DELAY 12
#define FTS_CMD_READ_ID 0x90
#define FTS_CMD_READ_ID_LEN 4
#define FTS_CMD_READ_ID_LEN_INCELL 1
#define FTS_CMD_READ_FW_CONF 0xA8
/*register address*/
#define FTS_REG_INT_CNT 0x8F
#define FTS_REG_FLOW_WORK_CNT 0x91
#define FTS_REG_WORKMODE 0x00
#define FTS_REG_WORKMODE_FACTORY_VALUE 0x40
#define FTS_REG_WORKMODE_WORK_VALUE 0x00
#define FTS_REG_ESDCHECK_DISABLE 0x8D
#define FTS_REG_CHIP_ID 0xA3
#define FTS_REG_CHIP_ID2 0x9F
#define FTS_REG_POWER_MODE 0xA5
#define FTS_REG_POWER_MODE_SLEEP 0x03
#define FTS_REG_FW_VER 0xA6
#define FTS_REG_VENDOR_ID 0xA8
#define FTS_REG_LCD_BUSY_NUM 0xAB
#define FTS_REG_FACE_DEC_MODE_EN 0xB0
#define FTS_REG_FACTORY_MODE_DETACH_FLAG 0xB4
#define FTS_REG_FACE_DEC_MODE_STATUS 0x01
#define FTS_REG_IDE_PARA_VER_ID 0xB5
#define FTS_REG_IDE_PARA_STATUS 0xB6
#define FTS_REG_GLOVE_MODE_EN 0xC0
#define FTS_REG_COVER_MODE_EN 0xC1
#define FTS_REG_REPORT_RATE 0x88
#define FTS_REG_CHARGER_MODE_EN 0x8B
#define FTS_REG_GESTURE_EN 0xD0
#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3
#define FTS_REG_MODULE_ID 0xE3
#define FTS_REG_LIC_VER 0xE4
#define FTS_REG_ESD_SATURATE 0xED
#define FTS_SYSFS_ECHO_ON(buf) (buf[0] == '1')
#define FTS_SYSFS_ECHO_OFF(buf) (buf[0] == '0')
#define kfree_safe(pbuf) do {\
if (pbuf) {\
kfree(pbuf);\
pbuf = NULL;\
}\
} while(0)
/*****************************************************************************
* Alternative mode (When something goes wrong,
* the modules may be able to solve the problem.)
*****************************************************************************/
/*
* point report check
* default: disable
*/
#define FTS_POINT_REPORT_CHECK_EN 0
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
struct ft_chip_t {
u64 type;
u8 chip_idh;
u8 chip_idl;
u8 rom_idh;
u8 rom_idl;
u8 pb_idh;
u8 pb_idl;
u8 bl_idh;
u8 bl_idl;
};
struct ts_ic_info {
bool is_incell;
bool hid_supported;
struct ft_chip_t ids;
};
/*****************************************************************************
* DEBUG function define here
*****************************************************************************/
#if FTS_DEBUG_EN
#define FTS_DEBUG(fmt, args...) do { \
printk("[FTS_TS]%s:"fmt"\n", __func__, ##args); \
} while (0)
#define FTS_FUNC_ENTER() do { \
printk("[FTS_TS]%s: Enter\n", __func__); \
} while (0)
#define FTS_FUNC_EXIT() do { \
printk("[FTS_TS]%s: Exit(%d)\n", __func__, __LINE__); \
} while (0)
#else /* #if FTS_DEBUG_EN*/
#define FTS_DEBUG(fmt, args...)
#define FTS_FUNC_ENTER()
#define FTS_FUNC_EXIT()
#endif
#define FTS_INFO(fmt, args...) do { \
printk(KERN_INFO "[FTS_TS/I]%s:"fmt"\n", __func__, ##args); \
} while (0)
#define FTS_ERROR(fmt, args...) do { \
printk(KERN_ERR "[FTS_TS/E]%s:"fmt"\n", __func__, ##args); \
} while (0)
#endif /* __LINUX_FOCALTECH_COMMON_H__ */

View File

@@ -0,0 +1,277 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, FocalTech Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/************************************************************************
*
* File Name: focaltech_config.h
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-08
*
* Abstract: global configurations
*
* Version: v1.0
*
************************************************************************/
#ifndef _LINUX_FOCLATECH_CONFIG_H_
#define _LINUX_FOCLATECH_CONFIG_H_
/**************************************************/
/****** G: A, I: B, S: C, U: D ******************/
/****** chip type defines, do not modify *********/
#define _FT8716 0x87160805
#define _FT8736 0x87360806
#define _FT8006M 0x80060807
#define _FT8607 0x86070809
#define _FT8006U 0x8006D80B
#define _FT8006S 0x8006A80B
#define _FT8613 0x8613080C
#define _FT8719 0x8719080D
#define _FT8739 0x8739080E
#define _FT8615 0x8615080F
#define _FT8201 0x82010810
#define _FT8006P 0x86220811
#define _FT7251 0x72510812
#define _FT7252 0x72520813
#define _FT8613S 0x8613C814
#define _FT8756 0x87560815
#define _FT8302 0x83020816
#define _FT8009 0x80090817
#define _FT8656 0x86560818
#define _FT8006S_AA 0x86320819
#define _FT7250 0x7250081A
#define _FT7120 0x7120081B
#define _FT8720 0x8720081C
#define _FT8016 0x8016081D
#define _FT5416 0x54160402
#define _FT5426 0x54260402
#define _FT5435 0x54350402
#define _FT5436 0x54360402
#define _FT5526 0x55260402
#define _FT5526I 0x5526B402
#define _FT5446 0x54460402
#define _FT5346 0x53460402
#define _FT5446I 0x5446B402
#define _FT5346I 0x5346B402
#define _FT7661 0x76610402
#define _FT7511 0x75110402
#define _FT7421 0x74210402
#define _FT7681 0x76810402
#define _FT3C47U 0x3C47D402
#define _FT3417 0x34170402
#define _FT3517 0x35170402
#define _FT3327 0x33270402
#define _FT3427 0x34270402
#define _FT7311 0x73110402
#define _FT5526_V00 0x5526C402
#define _FT5626 0x56260401
#define _FT5726 0x57260401
#define _FT5826B 0x5826B401
#define _FT5826S 0x5826C401
#define _FT7811 0x78110401
#define _FT3D47 0x3D470401
#define _FT3617 0x36170401
#define _FT3717 0x37170401
#define _FT3817B 0x3817B401
#define _FT3517U 0x3517D401
#define _FT6236U 0x6236D003
#define _FT6336G 0x6336A003
#define _FT6336U 0x6336D003
#define _FT6436U 0x6436D003
#define _FT6436T 0x6436E003
#define _FT3267 0x32670004
#define _FT3367 0x33670004
#define _FT3327DQQ_XXX 0x3327D482
#define _FT5446DQS_XXX 0x5446D482
#define _FT3427_003 0x3427D482
#define _FT3427G_003 0x3427A482
#define _FT5446_003 0x5446D482
#define _FT5446_Q03 0x5446C482
#define _FT5446_P03 0x5446A481
#define _FT5426_003 0x5426D482
#define _FT5526_003 0x5526D482
#define _FT3518 0x35180481
#define _FT3518U 0x3518D481
#define _FT3558 0x35580481
#define _FT3528 0x35280481
#define _FT5536 0x55360481
#define _FT5536L 0x5536E481
#define _FT3418 0x34180481
#define _FT5446U 0x5446D083
#define _FT5456U 0x5456D083
#define _FT3417U 0x3417D083
#define _FT5426U 0x5426D083
#define _FT3428 0x34280083
#define _FT3437U 0x3437D083
#define _FT7302 0x73020084
#define _FT7202 0x72020084
#define _FT3308 0x33080084
#define _FT6446 0x64460084
#define _FT6346U 0x6346D085
#define _FT6346G 0x6346A085
#define _FT3067 0x30670085
#define _FT3068 0x30680085
#define _FT3168 0x31680085
#define _FT3268 0x32680085
#define _FT6146 0x61460085
#define _FT5726_003 0x5726D486
#define _FT5726_V03 0x5726C486
#define _FT3618 0x36180487
#define _FT5646 0x56460487
#define _FT3A58 0x3A580487
#define _FT3B58 0x3B580487
#define _FT3D58 0x3D580487
#define _FT5936 0x59360487
#define _FT5A36 0x5A360487
#define _FT5B36 0x5B360487
#define _FT5D36 0x5D360487
#define _FT5946 0x59460487
#define _FT5A46 0x5A460487
#define _FT5B46 0x5B460487
#define _FT5D46 0x5D460487
#define _FT3658U 0x3658D488
/******************* Enables *********************/
/*********** 1 to enable, 0 to disable ***********/
/*
* show debug log info
* enable it for debug, disable it for release
*/
#define FTS_DEBUG_EN 0
/*
* Linux MultiTouch Protocol
* 1: Protocol B(default), 0: Protocol A
*/
#define FTS_MT_PROTOCOL_B_EN 1
/*
* Report Pressure in multitouch
* 1:enable(default),0:disable
*/
#define FTS_REPORT_PRESSURE_EN 1
/*
* Gesture function enable
* default: disable
*/
#define FTS_GESTURE_EN 0
/*
* ESD check & protection
* default: disable
*/
#define FTS_ESDCHECK_EN 0
/*
* Production test enable
* 1: enable, 0:disable(default)
*/
#define FTS_TEST_EN 0
/*
* Pinctrl enable
* default: disable
*/
#define FTS_PINCTRL_EN 1
/*
* Customer power enable
* enable it when customer need control TP power
* default: disable
*/
#define FTS_POWER_SOURCE_CUST_EN 1
/****************************************************/
/********************** Upgrade ****************************/
/*
* auto upgrade
*/
#define FTS_AUTO_UPGRADE_EN 1
/*
* auto upgrade for lcd cfg
*/
#define FTS_AUTO_LIC_UPGRADE_EN 0
/*
* Numbers of modules support
*/
#define FTS_GET_MODULE_NUM 0
/*
* module_id: mean vendor_id generally, also maybe gpio or lcm_id...
* If means vendor_id, the FTS_MODULE_ID = PANEL_ID << 8 + VENDOR_ID
* FTS_GET_MODULE_NUM == 0/1, no check module id, you may ignore them
* FTS_GET_MODULE_NUM >= 2, compatible with FTS_MODULE2_ID
* FTS_GET_MODULE_NUM >= 3, compatible with FTS_MODULE3_ID
*/
#define FTS_MODULE_ID 0x0000
#define FTS_MODULE2_ID 0x0000
#define FTS_MODULE3_ID 0x0000
/*
* Need set the following when get firmware via firmware_request()
* For example: if module'vendor is tianma,
* #define FTS_MODULE_NAME "tianma"
* then file_name will be "focaltech_ts_fw_tianma"
* You should rename fw to "focaltech_ts_fw_tianma", and push it into
* etc/firmware or by customers
*/
#define FTS_MODULE_NAME "gvo"
#define FTS_MODULE2_NAME ""
#define FTS_MODULE3_NAME ""
/*
* FW.i file for auto upgrade, you must replace it with your own
* define your own fw_file, the sample one to be replaced is invalid
* NOTE: if FTS_GET_MODULE_NUM > 1, it's the fw corresponding with FTS_VENDOR_ID
*/
#define FTS_UPGRADE_FW_FILE "include/firmware/fw_sample.i"
/*
* if FTS_GET_MODULE_NUM >= 2, fw corrsponding with FTS_VENDOR_ID2
* define your own fw_file, the sample one is invalid
*/
#define FTS_UPGRADE_FW2_FILE "include/firmware/fw_sample.i"
/*
* if FTS_GET_MODULE_NUM >= 3, fw corrsponding with FTS_VENDOR_ID3
* define your own fw_file, the sample one is invalid
*/
#define FTS_UPGRADE_FW3_FILE "include/firmware/fw_sample.i"
/*********************************************************/
#endif /* _LINUX_FOCLATECH_CONFIG_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,389 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_core.h
* Author: Focaltech Driver Team
*
* Created: 2016-08-08
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
#ifndef __LINUX_FOCALTECH_CORE_H__
#define __LINUX_FOCALTECH_CORE_H__
/*****************************************************************************
* Included header files
*****************************************************************************/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <asm/uaccess.h>
#include <linux/firmware.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/jiffies.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/dma-mapping.h>
#include <linux/gunyah/gh_irq_lend.h>
#include <linux/gunyah/gh_mem_notifier.h>
#include "focaltech_common.h"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define FTS_MAX_POINTS_SUPPORT 10 /* constant value, can't be changed */
#define FTS_MAX_KEYS 4
#define FTS_KEY_DIM 10
#define FTS_ONE_TCH_LEN 6
#define FTS_TOUCH_DATA_LEN (FTS_MAX_POINTS_SUPPORT * FTS_ONE_TCH_LEN + 3)
#define FTS_GESTURE_POINTS_MAX 6
#define FTS_GESTURE_DATA_LEN (FTS_GESTURE_POINTS_MAX * 4 + 4)
#define FTS_MAX_ID 0x0A
#define FTS_TOUCH_X_H_POS 3
#define FTS_TOUCH_X_L_POS 4
#define FTS_TOUCH_Y_H_POS 5
#define FTS_TOUCH_Y_L_POS 6
#define FTS_TOUCH_PRE_POS 7
#define FTS_TOUCH_AREA_POS 8
#define FTS_TOUCH_POINT_NUM 2
#define FTS_TOUCH_EVENT_POS 3
#define FTS_TOUCH_ID_POS 5
#define FTS_COORDS_ARR_SIZE 4
#define FTS_X_MIN_DISPLAY_DEFAULT 0
#define FTS_Y_MIN_DISPLAY_DEFAULT 0
#define FTS_X_MAX_DISPLAY_DEFAULT 720
#define FTS_Y_MAX_DISPLAY_DEFAULT 1280
#define FTS_TOUCH_DOWN 0
#define FTS_TOUCH_UP 1
#define FTS_TOUCH_CONTACT 2
#define EVENT_DOWN(flag) ((FTS_TOUCH_DOWN == flag) || (FTS_TOUCH_CONTACT == flag))
#define EVENT_UP(flag) (FTS_TOUCH_UP == flag)
#define EVENT_NO_DOWN(data) (!data->point_num)
#define FTX_MAX_COMPATIBLE_TYPE 4
#define FTX_MAX_COMMMAND_LENGTH 16
/*****************************************************************************
* Alternative mode (When something goes wrong, the modules may be able to solve the problem.)
*****************************************************************************/
/*
* For commnication error in PM(deep sleep) state
*/
#define FTS_PATCH_COMERR_PM 0
#define FTS_TIMEOUT_COMERR_PM 700
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
struct ftxxxx_proc {
struct proc_dir_entry *proc_entry;
u8 opmode;
u8 cmd_len;
u8 cmd[FTX_MAX_COMMMAND_LENGTH];
};
struct fts_ts_platform_data {
u32 type;
u32 irq_gpio;
u32 irq_gpio_flags;
u32 reset_gpio;
u32 reset_gpio_flags;
bool have_key;
u32 key_number;
u32 keys[FTS_MAX_KEYS];
u32 key_y_coords[FTS_MAX_KEYS];
u32 key_x_coords[FTS_MAX_KEYS];
u32 x_max;
u32 y_max;
u32 x_min;
u32 y_min;
u32 max_touch_number;
};
struct ts_event {
int x; /*x coordinate */
int y; /*y coordinate */
int p; /* pressure */
int flag; /* touch event flag: 0 -- down; 1-- up; 2 -- contact */
int id; /*touch ID */
int area;
};
enum trusted_touch_mode_config {
TRUSTED_TOUCH_VM_MODE,
TRUSTED_TOUCH_MODE_NONE
};
enum trusted_touch_pvm_states {
TRUSTED_TOUCH_PVM_INIT,
PVM_I2C_RESOURCE_ACQUIRED,
PVM_INTERRUPT_DISABLED,
PVM_IOMEM_LENT,
PVM_IOMEM_LENT_NOTIFIED,
PVM_IRQ_LENT,
PVM_IRQ_LENT_NOTIFIED,
PVM_IOMEM_RELEASE_NOTIFIED,
PVM_IRQ_RELEASE_NOTIFIED,
PVM_ALL_RESOURCES_RELEASE_NOTIFIED,
PVM_IRQ_RECLAIMED,
PVM_IOMEM_RECLAIMED,
PVM_INTERRUPT_ENABLED,
PVM_I2C_RESOURCE_RELEASED,
TRUSTED_TOUCH_PVM_STATE_MAX
};
enum trusted_touch_tvm_states {
TRUSTED_TOUCH_TVM_INIT,
TVM_IOMEM_LENT_NOTIFIED,
TVM_IRQ_LENT_NOTIFIED,
TVM_ALL_RESOURCES_LENT_NOTIFIED,
TVM_IOMEM_ACCEPTED,
TVM_I2C_SESSION_ACQUIRED,
TVM_IRQ_ACCEPTED,
TVM_INTERRUPT_ENABLED,
TVM_INTERRUPT_DISABLED,
TVM_IRQ_RELEASED,
TVM_I2C_SESSION_RELEASED,
TVM_IOMEM_RELEASED,
TRUSTED_TOUCH_TVM_STATE_MAX
};
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#define TRUSTED_TOUCH_MEM_LABEL 0x7
#define TOUCH_RESET_GPIO_BASE 0xF114000
#define TOUCH_RESET_GPIO_SIZE 0x1000
#define TOUCH_RESET_GPIO_OFFSET 0x4
#define TOUCH_INTR_GPIO_BASE 0xF115000
#define TOUCH_INTR_GPIO_SIZE 0x1000
#define TOUCH_INTR_GPIO_OFFSET 0x8
#define TRUSTED_TOUCH_EVENT_LEND_FAILURE -1
#define TRUSTED_TOUCH_EVENT_LEND_NOTIFICATION_FAILURE -2
#define TRUSTED_TOUCH_EVENT_ACCEPT_FAILURE -3
#define TRUSTED_TOUCH_EVENT_FUNCTIONAL_FAILURE -4
#define TRUSTED_TOUCH_EVENT_RELEASE_FAILURE -5
#define TRUSTED_TOUCH_EVENT_RECLAIM_FAILURE -6
#define TRUSTED_TOUCH_EVENT_I2C_FAILURE -7
#define TRUSTED_TOUCH_EVENT_NOTIFICATIONS_PENDING 5
struct trusted_touch_vm_info {
enum gh_irq_label irq_label;
enum gh_mem_notifier_tag mem_tag;
enum gh_vm_names vm_name;
const char *trusted_touch_type;
u32 hw_irq;
gh_memparcel_handle_t vm_mem_handle;
u32 *iomem_bases;
u32 *iomem_sizes;
u32 iomem_list_size;
void *mem_cookie;
atomic_t vm_state;
};
#endif
struct fts_ts_data {
struct i2c_client *client;
struct spi_device *spi;
struct device *dev;
struct input_dev *input_dev;
struct fts_ts_platform_data *pdata;
struct ts_ic_info ic_info;
struct workqueue_struct *ts_workqueue;
struct work_struct fwupg_work;
struct delayed_work esdcheck_work;
struct delayed_work prc_work;
struct work_struct resume_work;
struct work_struct suspend_work;
struct ftxxxx_proc proc;
spinlock_t irq_lock;
struct mutex report_mutex;
struct mutex bus_lock;
struct mutex transition_lock;
int irq;
int log_level;
int fw_is_running; /* confirm fw is running when using spi:default 0 */
int dummy_byte;
#if defined(CONFIG_PM) && FTS_PATCH_COMERR_PM
struct completion pm_completion;
bool pm_suspend;
#endif
bool suspended;
bool fw_loading;
bool irq_disabled;
bool power_disabled;
bool glove_mode;
bool cover_mode;
bool charger_mode;
bool gesture_mode; /* gesture enable or disable, default: disable */
int report_rate;
/* multi-touch */
struct ts_event *events;
u8 *bus_tx_buf;
u8 *bus_rx_buf;
int bus_type;
u8 *point_buf;
void *notifier_cookie;
int pnt_buf_size;
int touchs;
int key_state;
int touch_point;
int point_num;
struct regulator *vdd;
struct regulator *vcc_i2c;
#if FTS_PINCTRL_EN
struct pinctrl *pinctrl;
struct pinctrl_state *pins_active;
struct pinctrl_state *pins_suspend;
struct pinctrl_state *pins_release;
#endif
#if defined(CONFIG_FB) || defined(CONFIG_DRM)
struct notifier_block fb_notif;
#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
#ifdef CONFIG_FTS_TRUSTED_TOUCH
struct trusted_touch_vm_info *vm_info;
struct mutex fts_clk_io_ctrl_mutex;
const char *touch_environment;
struct completion trusted_touch_powerdown;
struct clk *core_clk;
struct clk *iface_clk;
atomic_t trusted_touch_initialized;
atomic_t trusted_touch_enabled;
atomic_t trusted_touch_transition;
atomic_t trusted_touch_event;
atomic_t trusted_touch_abort_status;
atomic_t delayed_vm_probe_pending;
atomic_t trusted_touch_mode;
#endif
};
enum _FTS_BUS_TYPE {
BUS_TYPE_NONE,
BUS_TYPE_I2C,
BUS_TYPE_SPI,
BUS_TYPE_SPI_V2,
};
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
extern struct fts_ts_data *fts_data;
/* communication interface */
int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen);
int fts_read_reg(u8 addr, u8 *value);
int fts_write(u8 *writebuf, u32 writelen);
int fts_write_reg(u8 addr, u8 value);
void fts_hid2std(void);
int fts_bus_init(struct fts_ts_data *ts_data);
int fts_bus_exit(struct fts_ts_data *ts_data);
/* Gesture functions */
int fts_gesture_init(struct fts_ts_data *ts_data);
int fts_gesture_exit(struct fts_ts_data *ts_data);
void fts_gesture_recovery(struct fts_ts_data *ts_data);
int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data);
int fts_gesture_suspend(struct fts_ts_data *ts_data);
int fts_gesture_resume(struct fts_ts_data *ts_data);
/* Apk and functions */
int fts_create_apk_debug_channel(struct fts_ts_data *);
void fts_release_apk_debug_channel(struct fts_ts_data *);
/* ADB functions */
int fts_create_sysfs(struct fts_ts_data *ts_data);
int fts_remove_sysfs(struct fts_ts_data *ts_data);
/* ESD */
#if FTS_ESDCHECK_EN
int fts_esdcheck_init(struct fts_ts_data *ts_data);
int fts_esdcheck_exit(struct fts_ts_data *ts_data);
int fts_esdcheck_switch(bool enable);
int fts_esdcheck_proc_busy(bool proc_debug);
int fts_esdcheck_set_intr(bool intr);
int fts_esdcheck_suspend(void);
int fts_esdcheck_resume(void);
#endif
/* Production test */
#if FTS_TEST_EN
int fts_test_init(struct fts_ts_data *ts_data);
int fts_test_exit(struct fts_ts_data *ts_data);
#endif
/* Point Report Check*/
#if FTS_POINT_REPORT_CHECK_EN
int fts_point_report_check_init(struct fts_ts_data *ts_data);
int fts_point_report_check_exit(struct fts_ts_data *ts_data);
void fts_prc_queue_work(struct fts_ts_data *ts_data);
#endif
/* FW upgrade */
int fts_fwupg_init(struct fts_ts_data *ts_data);
int fts_fwupg_exit(struct fts_ts_data *ts_data);
int fts_enter_test_environment(bool test_state);
/* Other */
int fts_reset_proc(int hdelayms);
int fts_wait_tp_to_valid(void);
void fts_release_all_finger(void);
void fts_tp_state_recovery(struct fts_ts_data *ts_data);
int fts_ex_mode_init(struct fts_ts_data *ts_data);
int fts_ex_mode_exit(struct fts_ts_data *ts_data);
int fts_ex_mode_recovery(struct fts_ts_data *ts_data);
void fts_irq_disable(void);
void fts_irq_enable(void);
int fts_ts_handle_trusted_touch_pvm(struct fts_ts_data *ts_data, int value);
int fts_ts_handle_trusted_touch_tvm(struct fts_ts_data *ts_data, int value);
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
void fts_ts_trusted_touch_tvm_i2c_failure_report(struct fts_ts_data *fts_data);
#endif
#endif
#endif /* __LINUX_FOCALTECH_CORE_H__ */

View File

@@ -0,0 +1,465 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, FocalTech Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_esdcheck.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-03
*
* Abstract: ESD check function
*
* Version: v1.0
*
* Revision History:
* v1.0:
* First release. By luougojin 2016-08-03
* v1.1: By luougojin 2017-02-15
* 1. Add LCD_ESD_PATCH to control idc_esdcheck_lcderror
*****************************************************************************/
/*****************************************************************************
* Included header files
*****************************************************************************/
#include "focaltech_core.h"
#if FTS_ESDCHECK_EN
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define ESDCHECK_WAIT_TIME 1000 /* ms */
#define LCD_ESD_PATCH 0
#define ESDCHECK_INTRCNT_MAX 2
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
struct fts_esdcheck_st {
u8 mode : 1; /* 1- need check esd 0- no esd check */
u8 suspend : 1;
u8 proc_debug : 1; /* apk or adb use */
u8 intr : 1; /* 1- Interrupt trigger */
u8 unused : 4;
u8 intr_cnt;
u8 flow_work_hold_cnt; /* Flow Work Cnt(reg0x91) keep a same value for x times. >=5 times is ESD, need reset */
u8 flow_work_cnt_last; /* Save Flow Work Cnt(reg0x91) value */
u32 hardware_reset_cnt;
u32 nack_cnt;
u32 dataerror_cnt;
};
/*****************************************************************************
* Static variables
*****************************************************************************/
static struct fts_esdcheck_st fts_esdcheck_data;
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
/*****************************************************************************
* functions body
*****************************************************************************/
#if LCD_ESD_PATCH
int lcd_need_reset;
static int tp_need_recovery; /* LCD reset cause Tp reset */
int idc_esdcheck_lcderror(struct fts_ts_data *ts_data)
{
int ret = 0;
u8 val = 0;
FTS_DEBUG("check LCD ESD");
if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) {
tp_need_recovery = 0;
/* LCD reset, need recover TP state */
fts_release_all_finger();
fts_tp_state_recovery(ts_data);
}
ret = fts_read_reg(FTS_REG_ESD_SATURATE, &val);
if ( ret < 0) {
FTS_ERROR("read reg0xED fail,ret:%d", ret);
return -EIO;
}
if (val == 0xAA) {
/*
* 1. Set flag lcd_need_reset = 1;
* 2. LCD driver need reset(recovery) LCD and set lcd_need_reset to 0
* 3. recover TP state
*/
FTS_INFO("LCD ESD, need execute LCD reset");
lcd_need_reset = 1;
tp_need_recovery = 1;
}
return 0;
}
#endif
static int fts_esdcheck_tp_reset(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
fts_esdcheck_data.flow_work_hold_cnt = 0;
fts_esdcheck_data.hardware_reset_cnt++;
fts_reset_proc(200);
fts_release_all_finger();
fts_tp_state_recovery(ts_data);
FTS_FUNC_EXIT();
return 0;
}
static bool get_chip_id(struct fts_ts_data *ts_data)
{
int ret = 0;
int i = 0;
u8 reg_value = 0;
u8 reg_addr = 0;
u8 chip_id = ts_data->ic_info.ids.chip_idh;
for (i = 0; i < 3; i++) {
reg_addr = FTS_REG_CHIP_ID;
ret = fts_read(&reg_addr, 1, &reg_value, 1);
if (ret < 0) {
FTS_ERROR("read chip id fail,ret:%d", ret);
fts_esdcheck_data.nack_cnt++;
} else {
if (reg_value == chip_id) {
break;
} else {
FTS_DEBUG("read chip_id:%x,retry:%d", reg_value, i);
fts_esdcheck_data.dataerror_cnt++;
}
}
msleep(10);
}
/* if can't get correct data in 3 times, then need hardware reset */
if (i >= 3) {
FTS_ERROR("read chip id 3 times fail, need execute TP reset");
return true;
}
return false;
}
/*****************************************************************************
* Name: get_flow_cnt
* Brief: Read flow cnt(0x91)
* Input:
* Output:
* Return: 1(true) - Reg 0x91(flow cnt) abnormal: hold a value for 5 times
* 0(false) - Reg 0x91(flow cnt) normal
*****************************************************************************/
static bool get_flow_cnt(struct fts_ts_data *ts_data)
{
int ret = 0;
u8 reg_value = 0;
u8 reg_addr = 0;
reg_addr = FTS_REG_FLOW_WORK_CNT;
ret = fts_read(&reg_addr, 1, &reg_value, 1);
if (ret < 0) {
FTS_ERROR("read reg0x91 fail,ret:%d", ret);
fts_esdcheck_data.nack_cnt++;
} else {
if ( reg_value == fts_esdcheck_data.flow_work_cnt_last ) {
FTS_DEBUG("reg0x91,val:%x,last:%x", reg_value,
fts_esdcheck_data.flow_work_cnt_last);
fts_esdcheck_data.flow_work_hold_cnt++;
} else {
fts_esdcheck_data.flow_work_hold_cnt = 0;
}
fts_esdcheck_data.flow_work_cnt_last = reg_value;
}
/* Flow Work Cnt keep a value for 5 times, need execute TP reset */
if (fts_esdcheck_data.flow_work_hold_cnt >= 5) {
FTS_DEBUG("reg0x91 keep a value for 5 times, need execute TP reset");
return true;
}
return false;
}
static int esdcheck_algorithm(struct fts_ts_data *ts_data)
{
int ret = 0;
u8 reg_value = 0;
u8 reg_addr = 0;
bool hardware_reset = 0;
/* 1. esdcheck is interrupt, then return */
if (fts_esdcheck_data.intr == 1) {
fts_esdcheck_data.intr_cnt++;
if (fts_esdcheck_data.intr_cnt > ESDCHECK_INTRCNT_MAX)
fts_esdcheck_data.intr = 0;
else
return 0;
}
/* 2. check power state, if suspend, no need check esd */
if (fts_esdcheck_data.suspend == 1) {
FTS_DEBUG("In suspend, not check esd");
/* because in suspend state, adb can be used, when upgrade FW, will
* active ESD check(active = 1); But in suspend, then will don't
* queue_delayed_work, when resume, don't check ESD again
*/
return 0;
}
/* 3. check fts_esdcheck_data.proc_debug state, if 1-proc busy, no need check esd*/
if (fts_esdcheck_data.proc_debug == 1) {
FTS_INFO("In apk/adb command mode, not check esd");
return 0;
}
/* 4. In factory mode, can't check esd */
reg_addr = FTS_REG_WORKMODE;
ret = fts_read_reg(reg_addr, &reg_value);
if ( ret < 0 ) {
fts_esdcheck_data.nack_cnt++;
} else if ( (reg_value & 0x70) != FTS_REG_WORKMODE_WORK_VALUE) {
FTS_DEBUG("not in work mode(%x), no check esd", reg_value);
return 0;
}
/* 5. IDC esd check lcd default:close */
#if LCD_ESD_PATCH
idc_esdcheck_lcderror(ts_data);
#endif
/* 6. Get Chip ID */
hardware_reset = get_chip_id(ts_data);
/* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */
if (!hardware_reset) {
hardware_reset = get_flow_cnt(ts_data);
}
/* 8. If need hardware reset, then handle it here */
if (hardware_reset == 1) {
FTS_DEBUG("NoACK=%d, Error Data=%d, Hardware Reset=%d",
fts_esdcheck_data.nack_cnt,
fts_esdcheck_data.dataerror_cnt,
fts_esdcheck_data.hardware_reset_cnt);
fts_esdcheck_tp_reset(ts_data);
}
return 0;
}
static void esdcheck_func(struct work_struct *work)
{
struct fts_ts_data *ts_data = container_of(work,
struct fts_ts_data, esdcheck_work.work);
if (ENABLE == fts_esdcheck_data.mode) {
esdcheck_algorithm(ts_data);
queue_delayed_work(ts_data->ts_workqueue,
&ts_data->esdcheck_work,
msecs_to_jiffies(ESDCHECK_WAIT_TIME));
}
}
int fts_esdcheck_set_intr(bool intr)
{
/* interrupt don't add debug message */
fts_esdcheck_data.intr = intr;
fts_esdcheck_data.intr_cnt = (u8)intr;
return 0;
}
static int fts_esdcheck_get_status(void)
{
/* interrupt don't add debug message */
return fts_esdcheck_data.mode;
}
/*****************************************************************************
* Name: fts_esdcheck_proc_busy
* Brief: When APK or ADB command access TP via driver, then need set proc_debug,
* then will not check ESD.
* Input:
* Output:
* Return:
*****************************************************************************/
int fts_esdcheck_proc_busy(bool proc_debug)
{
fts_esdcheck_data.proc_debug = proc_debug;
return 0;
}
/*****************************************************************************
* Name: fts_esdcheck_switch
* Brief: FTS esd check function switch.
* Input: enable: 1 - Enable esd check
* 0 - Disable esd check
* Output:
* Return:
*****************************************************************************/
int fts_esdcheck_switch(bool enable)
{
struct fts_ts_data *ts_data = fts_data;
FTS_FUNC_ENTER();
if (fts_esdcheck_data.mode == ENABLE) {
if (enable) {
FTS_DEBUG("ESD check start");
fts_esdcheck_data.flow_work_hold_cnt = 0;
fts_esdcheck_data.flow_work_cnt_last = 0;
fts_esdcheck_data.intr = 0;
fts_esdcheck_data.intr_cnt = 0;
queue_delayed_work(ts_data->ts_workqueue,
&ts_data->esdcheck_work,
msecs_to_jiffies(ESDCHECK_WAIT_TIME));
} else {
FTS_DEBUG("ESD check stop");
cancel_delayed_work_sync(&ts_data->esdcheck_work);
}
}
FTS_FUNC_EXIT();
return 0;
}
int fts_esdcheck_suspend(void)
{
FTS_FUNC_ENTER();
fts_esdcheck_switch(DISABLE);
fts_esdcheck_data.suspend = 1;
fts_esdcheck_data.intr = 0;
fts_esdcheck_data.intr_cnt = 0;
FTS_FUNC_EXIT();
return 0;
}
int fts_esdcheck_resume( void )
{
FTS_FUNC_ENTER();
fts_esdcheck_switch(ENABLE);
fts_esdcheck_data.suspend = 0;
fts_esdcheck_data.intr = 0;
fts_esdcheck_data.intr_cnt = 0;
FTS_FUNC_EXIT();
return 0;
}
static ssize_t fts_esdcheck_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct input_dev *input_dev = fts_data->input_dev;
mutex_lock(&input_dev->mutex);
if (FTS_SYSFS_ECHO_ON(buf)) {
FTS_DEBUG("enable esdcheck");
fts_esdcheck_data.mode = ENABLE;
fts_esdcheck_switch(ENABLE);
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
FTS_DEBUG("disable esdcheck");
fts_esdcheck_switch(DISABLE);
fts_esdcheck_data.mode = DISABLE;
}
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_esdcheck_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count;
struct input_dev *input_dev = fts_data->input_dev;
mutex_lock(&input_dev->mutex);
count = snprintf(buf, PAGE_SIZE, "Esd check: %s\n", \
fts_esdcheck_get_status() ? "On" : "Off");
mutex_unlock(&input_dev->mutex);
return count;
}
/* sysfs esd node
* read example: cat fts_esd_mode ---read esd mode
* write example:echo 01 > fts_esd_mode ---make esdcheck enable
*
*/
static DEVICE_ATTR (fts_esd_mode, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store);
static struct attribute *fts_esd_mode_attrs[] = {
&dev_attr_fts_esd_mode.attr,
NULL,
};
static struct attribute_group fts_esd_group = {
.attrs = fts_esd_mode_attrs,
};
int fts_create_esd_sysfs(struct device *dev)
{
int ret = 0;
ret = sysfs_create_group(&dev->kobj, &fts_esd_group);
if ( ret != 0) {
FTS_ERROR("fts_create_esd_sysfs(sysfs) create fail");
sysfs_remove_group(&dev->kobj, &fts_esd_group);
return ret;
}
return 0;
}
int fts_esdcheck_init(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
if (ts_data->ts_workqueue) {
INIT_DELAYED_WORK(&ts_data->esdcheck_work, esdcheck_func);
} else {
FTS_ERROR("fts workqueue is NULL, can't run esd check func!");
return -EINVAL;
}
memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st));
fts_esdcheck_data.mode = ENABLE;
fts_esdcheck_data.intr = 0;
fts_esdcheck_data.intr_cnt = 0;
fts_esdcheck_switch(ENABLE);
fts_create_esd_sysfs(ts_data->dev);
FTS_FUNC_EXIT();
return 0;
}
int fts_esdcheck_exit(struct fts_ts_data *ts_data)
{
sysfs_remove_group(&ts_data->dev->kobj, &fts_esd_group);
return 0;
}
#endif /* FTS_ESDCHECK_EN */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,359 @@
/*
*
* FocalTech ftxxxx TouchScreen driver.
*
* Copyright (c) 2012-2019, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_ex_mode.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-31
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "focaltech_core.h"
/*****************************************************************************
* 2.Private constant and macro definitions using #define
*****************************************************************************/
/*****************************************************************************
* 3.Private enumerations, structures and unions using typedef
*****************************************************************************/
enum _ex_mode {
MODE_GLOVE = 0,
MODE_COVER,
MODE_CHARGER,
REPORT_RATE,
};
/*****************************************************************************
* 4.Static variables
*****************************************************************************/
/*****************************************************************************
* 5.Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* 6.Static function prototypes
*******************************************************************************/
static int fts_ex_mode_switch(enum _ex_mode mode, u8 value)
{
int ret = 0;
switch (mode) {
case MODE_GLOVE:
ret = fts_write_reg(FTS_REG_GLOVE_MODE_EN, value > 0 ? 1 : 0);
if (ret < 0)
FTS_ERROR("MODE_GLOVE switch to %d fail", value);
break;
case MODE_COVER:
ret = fts_write_reg(FTS_REG_COVER_MODE_EN, value > 0 ? 1 : 0);
if (ret < 0)
FTS_ERROR("MODE_COVER switch to %d fail", value);
break;
case MODE_CHARGER:
ret = fts_write_reg(FTS_REG_CHARGER_MODE_EN, value > 0 ? 1 : 0);
if (ret < 0)
FTS_ERROR("MODE_CHARGER switch to %d fail", value);
break;
case REPORT_RATE:
ret = fts_write_reg(FTS_REG_REPORT_RATE, value);
if (ret < 0)
FTS_ERROR("REPORT_RATE switch to %d fail", value);
break;
default:
FTS_ERROR("mode(%d) unsupport", mode);
ret = -EINVAL;
break;
}
return ret;
}
static ssize_t fts_glove_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
u8 val = 0;
struct fts_ts_data *ts_data = fts_data;
struct input_dev *input_dev = ts_data->input_dev;
mutex_lock(&input_dev->mutex);
fts_read_reg(FTS_REG_GLOVE_MODE_EN, &val);
count = scnprintf(buf + count, PAGE_SIZE, "Glove Mode:%s\n",
ts_data->glove_mode ? "On" : "Off");
count += scnprintf(buf + count, PAGE_SIZE - count,
"Glove Reg(0xC0):%d\n", val);
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_glove_mode_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
struct fts_ts_data *ts_data = fts_data;
if (FTS_SYSFS_ECHO_ON(buf)) {
if (!ts_data->glove_mode) {
FTS_DEBUG("enter glove mode");
ret = fts_ex_mode_switch(MODE_GLOVE, ENABLE);
if (ret >= 0) {
ts_data->glove_mode = ENABLE;
}
}
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
if (ts_data->glove_mode) {
FTS_DEBUG("exit glove mode");
ret = fts_ex_mode_switch(MODE_GLOVE, DISABLE);
if (ret >= 0) {
ts_data->glove_mode = DISABLE;
}
}
}
FTS_DEBUG("glove mode:%d", ts_data->glove_mode);
return count;
}
static ssize_t fts_cover_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
u8 val = 0;
struct fts_ts_data *ts_data = fts_data;
struct input_dev *input_dev = ts_data->input_dev;
mutex_lock(&input_dev->mutex);
fts_read_reg(FTS_REG_COVER_MODE_EN, &val);
count = scnprintf(buf + count, PAGE_SIZE, "Cover Mode:%s\n",
ts_data->cover_mode ? "On" : "Off");
count += scnprintf(buf + count, PAGE_SIZE - count,
"Cover Reg(0xC1):%d\n", val);
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_cover_mode_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
struct fts_ts_data *ts_data = fts_data;
if (FTS_SYSFS_ECHO_ON(buf)) {
if (!ts_data->cover_mode) {
FTS_DEBUG("enter cover mode");
ret = fts_ex_mode_switch(MODE_COVER, ENABLE);
if (ret >= 0) {
ts_data->cover_mode = ENABLE;
}
}
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
if (ts_data->cover_mode) {
FTS_DEBUG("exit cover mode");
ret = fts_ex_mode_switch(MODE_COVER, DISABLE);
if (ret >= 0) {
ts_data->cover_mode = DISABLE;
}
}
}
FTS_DEBUG("cover mode:%d", ts_data->cover_mode);
return count;
}
static ssize_t fts_charger_mode_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
u8 val = 0;
struct fts_ts_data *ts_data = fts_data;
struct input_dev *input_dev = ts_data->input_dev;
mutex_lock(&input_dev->mutex);
fts_read_reg(FTS_REG_CHARGER_MODE_EN, &val);
count = scnprintf(buf + count, PAGE_SIZE, "Charger Mode:%s\n",
ts_data->charger_mode ? "On" : "Off");
count += scnprintf(buf + count, PAGE_SIZE - count,
"Charger Reg(0x8B):%d\n", val);
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_charger_mode_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
struct fts_ts_data *ts_data = fts_data;
if (FTS_SYSFS_ECHO_ON(buf)) {
if (!ts_data->charger_mode) {
FTS_DEBUG("enter charger mode");
ret = fts_ex_mode_switch(MODE_CHARGER, ENABLE);
if (ret >= 0) {
ts_data->charger_mode = ENABLE;
}
}
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
if (ts_data->charger_mode) {
FTS_DEBUG("exit charger mode");
ret = fts_ex_mode_switch(MODE_CHARGER, DISABLE);
if (ret >= 0) {
ts_data->charger_mode = DISABLE;
}
}
}
FTS_DEBUG("charger mode:%d", ts_data->glove_mode);
return count;
}
static ssize_t fts_report_rate_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
u8 val = 0;
struct fts_ts_data *ts_data = fts_data;
struct input_dev *input_dev = ts_data->input_dev;
mutex_lock(&input_dev->mutex);
fts_read_reg(FTS_REG_REPORT_RATE, &val);
count = scnprintf(buf + count, PAGE_SIZE,
"Report Rate:%d\n", ts_data->report_rate);
count += scnprintf(buf + count, PAGE_SIZE - count,
"Report Rate Reg(0x88):%d\n", val);
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_report_rate_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int ret = 0;
struct fts_ts_data *ts_data = fts_data;
int rate;
ret = kstrtoint(buf, 16, &rate);
if (ret)
return ret;
if (rate != ts_data->report_rate) {
ret = fts_ex_mode_switch(REPORT_RATE, (u8)rate);
if (ret >= 0)
ts_data->report_rate = rate;
}
FTS_DEBUG("report rate:%d", ts_data->report_rate);
return count;
}
/* read and write charger mode
* read example: cat fts_glove_mode ---read glove mode
* write example:echo 1 > fts_glove_mode ---write glove mode to 01
*/
static DEVICE_ATTR(fts_glove_mode, S_IRUGO | S_IWUSR,
fts_glove_mode_show, fts_glove_mode_store);
static DEVICE_ATTR(fts_cover_mode, S_IRUGO | S_IWUSR,
fts_cover_mode_show, fts_cover_mode_store);
static DEVICE_ATTR(fts_charger_mode, S_IRUGO | S_IWUSR,
fts_charger_mode_show, fts_charger_mode_store);
static DEVICE_ATTR_RW(fts_report_rate);
static struct attribute *fts_touch_mode_attrs[] = {
&dev_attr_fts_glove_mode.attr,
&dev_attr_fts_cover_mode.attr,
&dev_attr_fts_charger_mode.attr,
&dev_attr_fts_report_rate.attr,
NULL,
};
static struct attribute_group fts_touch_mode_group = {
.attrs = fts_touch_mode_attrs,
};
int fts_ex_mode_recovery(struct fts_ts_data *ts_data)
{
if (ts_data->glove_mode) {
fts_ex_mode_switch(MODE_GLOVE, ENABLE);
}
if (ts_data->cover_mode) {
fts_ex_mode_switch(MODE_COVER, ENABLE);
}
if (ts_data->charger_mode) {
fts_ex_mode_switch(MODE_CHARGER, ENABLE);
}
if (ts_data->report_rate > 0)
fts_ex_mode_switch(REPORT_RATE, ts_data->report_rate);
return 0;
}
int fts_ex_mode_init(struct fts_ts_data *ts_data)
{
int ret = 0;
ts_data->glove_mode = DISABLE;
ts_data->cover_mode = DISABLE;
ts_data->charger_mode = DISABLE;
ts_data->report_rate = 0;
ret = sysfs_create_group(&ts_data->dev->kobj, &fts_touch_mode_group);
if (ret < 0) {
FTS_ERROR("create sysfs(ex_mode) fail");
sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group);
return ret;
} else {
FTS_DEBUG("create sysfs(ex_mode) succeedfully");
}
return 0;
}
int fts_ex_mode_exit(struct fts_ts_data *ts_data)
{
sysfs_remove_group(&ts_data->dev->kobj, &fts_touch_mode_group);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,216 @@
/************************************************************************
* Copyright (C) 2012-2019, Focaltech Systems (R)<29><>All Rights Reserved.
*
* File Name: focaltech_flash.h
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-07
*
* Abstract:
*
************************************************************************/
#ifndef __LINUX_FOCALTECH_FLASH_H__
#define __LINUX_FOCALTECH_FLASH_H__
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "focaltech_core.h"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define FTS_CMD_RESET 0x07
#define FTS_ROMBOOT_CMD_SET_PRAM_ADDR 0xAD
#define FTS_ROMBOOT_CMD_SET_PRAM_ADDR_LEN 4
#define FTS_ROMBOOT_CMD_WRITE 0xAE
#define FTS_ROMBOOT_CMD_START_APP 0x08
#define FTS_DELAY_PRAMBOOT_START 100
#define FTS_ROMBOOT_CMD_ECC 0xCC
#define FTS_PRAM_SADDR 0x000000
#define FTS_DRAM_SADDR 0xD00000
#define FTS_CMD_READ 0x03
#define FTS_CMD_READ_DELAY 1
#define FTS_CMD_READ_LEN 4
#define FTS_CMD_READ_LEN_SPI 6
#define FTS_CMD_FLASH_TYPE 0x05
#define FTS_CMD_FLASH_MODE 0x09
#define FLASH_MODE_WRITE_FLASH_VALUE 0x0A
#define FLASH_MODE_UPGRADE_VALUE 0x0B
#define FLASH_MODE_LIC_VALUE 0x0C
#define FLASH_MODE_PARAM_VALUE 0x0D
#define FTS_CMD_ERASE_APP 0x61
#define FTS_REASE_APP_DELAY 1350
#define FTS_ERASE_SECTOR_DELAY 60
#define FTS_RETRIES_REASE 50
#define FTS_RETRIES_DELAY_REASE 400
#define FTS_CMD_FLASH_STATUS 0x6A
#define FTS_CMD_FLASH_STATUS_LEN 2
#define FTS_CMD_FLASH_STATUS_NOP 0x0000
#define FTS_CMD_FLASH_STATUS_ECC_OK 0xF055
#define FTS_CMD_FLASH_STATUS_ERASE_OK 0xF0AA
#define FTS_CMD_FLASH_STATUS_WRITE_OK 0x1000
#define FTS_CMD_ECC_INIT 0x64
#define FTS_CMD_ECC_CAL 0x65
#define FTS_CMD_ECC_CAL_LEN 7
#define FTS_RETRIES_ECC_CAL 10
#define FTS_RETRIES_DELAY_ECC_CAL 50
#define FTS_CMD_ECC_READ 0x66
#define FTS_CMD_SET_WFLASH_ADDR 0xAB
#define FTS_CMD_SET_RFLASH_ADDR 0xAC
#define FTS_LEN_SET_ADDR 4
#define FTS_CMD_DATA_LEN 0xB0
#define FTS_CMD_APP_DATA_LEN_INCELL 0x7A
#define FTS_CMD_DATA_LEN_LEN 4
#define FTS_CMD_WRITE 0xBF
#define FTS_RETRIES_WRITE 100
#define FTS_RETRIES_DELAY_WRITE 1
#define FTS_CMD_WRITE_LEN 6
#define FTS_DELAY_READ_ID 20
#define FTS_DELAY_UPGRADE_RESET 80
#define PRAMBOOT_MIN_SIZE 0x120
#define PRAMBOOT_MAX_SIZE (64*1024)
#define FTS_FLASH_PACKET_LENGTH 32 /* max=128 */
#define FTS_MAX_LEN_ECC_CALC 0xFFFE /* must be even */
#define FTS_MIN_LEN 0x120
#define FTS_MAX_LEN_FILE (128 * 1024)
#define FTS_MAX_LEN_APP (64 * 1024)
#define FTS_MAX_LEN_SECTOR (4 * 1024)
#define FTS_CONIFG_VENDORID_OFF 0x04
#define FTS_CONIFG_MODULEID_OFF 0x1E
#define FTS_CONIFG_PROJECTID_OFF 0x20
#define FTS_APPINFO_OFF 0x100
#define FTS_APPINFO_APPLEN_OFF 0x00
#define FTS_APPINFO_APPLEN2_OFF 0x12
#define FTS_REG_UPGRADE 0xFC
#define FTS_REG_UPGRADE2 0xBC
#define FTS_UPGRADE_AA 0xAA
#define FTS_UPGRADE_55 0x55
#define FTS_DELAY_UPGRADE_AA 10
#define FTS_UPGRADE_LOOP 30
#define FTS_HEADER_LEN 32
#define FTS_FW_BIN_FILEPATH "/sdcard/"
#define FTS_FW_IDE_SIG "IDE_"
#define FTS_FW_IDE_SIG_LEN 4
#define MAX_MODULE_VENDOR_NAME_LEN 16
#define FTS_ROMBOOT_CMD_ECC_NEW_LEN 7
#define FTS_ECC_FINISH_TIMEOUT 100
#define FTS_ROMBOOT_CMD_ECC_FINISH 0xCE
#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_A5 0xA5
#define FTS_ROMBOOT_CMD_ECC_FINISH_OK_00 0x00
#define FTS_ROMBOOT_CMD_ECC_READ 0xCD
#define AL2_FCS_COEF ((1 << 15) + (1 << 10) + (1 << 3))
#define FTS_APP_INFO_OFFSET 0x100
enum FW_STATUS {
FTS_RUN_IN_ERROR,
FTS_RUN_IN_APP,
FTS_RUN_IN_ROM,
FTS_RUN_IN_PRAM,
FTS_RUN_IN_BOOTLOADER,
};
enum FW_FLASH_MODE {
FLASH_MODE_APP,
FLASH_MODE_LIC,
FLASH_MODE_PARAM,
FLASH_MODE_ALL,
};
enum ECC_CHECK_MODE {
ECC_CHECK_MODE_XOR,
ECC_CHECK_MODE_CRC16,
};
enum UPGRADE_SPEC {
UPGRADE_SPEC_V_1_0 = 0x0100,
};
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/* IC info */
struct upgrade_func {
u64 ctype[FTX_MAX_COMPATIBLE_TYPE];
u32 fwveroff;
u32 fwcfgoff;
u32 appoff;
u32 licoff;
u32 paramcfgoff;
u32 paramcfgveroff;
u32 paramcfg2off;
int pram_ecc_check_mode;
int fw_ecc_check_mode;
int upgspec_version;
bool new_return_value_from_ic;
bool appoff_handle_in_ic;
bool is_reset_register_BC;
bool read_boot_id_need_reset;
bool hid_supported;
bool pramboot_supported;
u8 *pramboot;
u32 pb_length;
int (*init)(u8 *, u32);
int (*write_pramboot_private)(void);
int (*upgrade)(u8 *, u32);
int (*get_hlic_ver)(u8 *);
int (*lic_upgrade)(u8 *, u32);
int (*param_upgrade)(u8 *, u32);
int (*force_upgrade)(u8 *, u32);
};
struct upgrade_setting_nf {
u8 rom_idh;
u8 rom_idl;
u16 reserved;
u32 app2_offset;
u32 ecclen_max;
u8 eccok_val;
u8 upgsts_boot;
u8 delay_init;
bool spi_pe;
bool half_length;
bool fd_check;
bool drwr_support;
};
struct upgrade_module {
int id;
char vendor_name[MAX_MODULE_VENDOR_NAME_LEN];
u8 *fw_file;
u32 fw_len;
};
struct fts_upgrade {
struct fts_ts_data *ts_data;
struct upgrade_module *module_info;
struct upgrade_func *func;
struct upgrade_setting_nf *setting_nf;
int module_id;
bool fw_from_request;
u8 *fw;
u32 fw_length;
u8 *lic;
u32 lic_length;
};
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
extern struct upgrade_func upgrade_func_ft5452;
extern struct upgrade_func upgrade_func_ft5652;
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
int fts_fwupg_reset_in_boot(void);
int fts_fwupg_enter_into_boot(void);
int fts_fwupg_erase(u32 delay);
int fts_fwupg_ecc_cal(u32 saddr, u32 len);
int fts_flash_write_buf(u32 saddr, u8 *buf, u32 len, u32 delay);
int fts_fwupg_upgrade(struct fts_upgrade *upg);
#endif

View File

@@ -0,0 +1,292 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2012-2019, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_upgrade_ft5452.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-15
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "../focaltech_flash.h"
/************************************************************************
* Name: fts_ft5452_upgrade
* Brief:
* Input:
* Output:
* Return: return 0 if success, otherwise return error code
***********************************************************************/
static int fts_ft5452_upgrade(u8 *buf, u32 len)
{
int ret = 0;
u32 start_addr = 0;
u8 cmd[4] = { 0 };
int ecc_in_host = 0;
int ecc_in_tp = 0;
int i = 0;
u8 wbuf[7] = { 0 };
u8 reg_val[4] = {0};
if (NULL == buf) {
FTS_ERROR("fw buf is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > (60 * 1024))) {
FTS_ERROR("fw buffer len(%x) fail", len);
return -EINVAL;
}
/* enter into upgrade environment */
ret = fts_fwupg_enter_into_boot();
if (ret < 0) {
FTS_ERROR("enter into pramboot/bootloader fail,ret=%d", ret);
goto fw_reset;
}
cmd[0] = FTS_CMD_FLASH_MODE;
cmd[1] = FLASH_MODE_UPGRADE_VALUE;
ret = fts_write(cmd, 2);
if (ret < 0) {
FTS_ERROR("upgrade mode(09) cmd write fail");
goto fw_reset;
}
cmd[0] = FTS_CMD_DATA_LEN;
cmd[1] = BYTE_OFF_16(len);
cmd[2] = BYTE_OFF_8(len);
cmd[3] = BYTE_OFF_0(len);
ret = fts_write(cmd, FTS_CMD_DATA_LEN_LEN);
if (ret < 0) {
FTS_ERROR("data len cmd write fail");
goto fw_reset;
}
ret = fts_fwupg_erase(FTS_REASE_APP_DELAY);
if (ret < 0) {
FTS_ERROR("erase cmd write fail");
goto fw_reset;
}
/* write app */
start_addr = upgrade_func_ft5452.appoff;
ecc_in_host = fts_flash_write_buf(start_addr, buf, len, 1);
if (ecc_in_host < 0 ) {
FTS_ERROR("lcd initial code write fail");
goto fw_reset;
}
FTS_INFO( "**********read out checksum**********");
/* check sum init */
wbuf[0] = FTS_CMD_ECC_INIT;
ret = fts_write(wbuf, 1);
if (ret < 0) {
FTS_ERROR("ecc init cmd write fail");
return ret;
}
/* send commond to start checksum */
wbuf[0] = FTS_CMD_ECC_CAL;
wbuf[1] = BYTE_OFF_16(start_addr);
wbuf[2] = BYTE_OFF_8(start_addr);
wbuf[3] = BYTE_OFF_0(start_addr);
wbuf[4] = BYTE_OFF_16(len);
wbuf[5] = BYTE_OFF_8(len);
wbuf[6] = BYTE_OFF_0(len);
FTS_DEBUG("ecc calc startaddr:0x%04x, len:%d", start_addr, len);
ret = fts_write(wbuf, 7);
if (ret < 0) {
FTS_ERROR("ecc calc cmd write fail");
return ret;
}
msleep(len / 256);
/* read status if check sum is finished */
for (i = 0; i < FTS_RETRIES_ECC_CAL; i++) {
wbuf[0] = FTS_CMD_FLASH_STATUS;
reg_val[0] = reg_val[1] = 0x00;
fts_read(wbuf, 1, reg_val, 2);
FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", reg_val[0], reg_val[1]);
if ((0xF0 == reg_val[0]) && (0x55 == reg_val[1])) {
break;
}
msleep(FTS_RETRIES_DELAY_ECC_CAL);
}
/* read out check sum */
wbuf[0] = FTS_CMD_ECC_READ;
ret = fts_read(wbuf, 1, reg_val, 1);
if (ret < 0) {
FTS_ERROR( "ecc read cmd write fail");
return ret;
}
ecc_in_tp = reg_val[0];
FTS_INFO("ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host);
if (ecc_in_tp != ecc_in_host) {
FTS_ERROR("ecc check fail");
goto fw_reset;
}
FTS_INFO("upgrade success, reset to normal boot");
ret = fts_fwupg_reset_in_boot();
if (ret < 0) {
FTS_ERROR("reset to normal boot fail");
}
msleep(200);
return 0;
fw_reset:
FTS_INFO("upgrade fail, reset to normal boot");
ret = fts_fwupg_reset_in_boot();
if (ret < 0) {
FTS_ERROR("reset to normal boot fail");
}
return -EIO;
}
struct upgrade_func upgrade_func_ft5452 = {
.ctype = {0x81},
.fwveroff = 0x010E,
.fwcfgoff = 0x1FFB0,
.appoff = 0x0000,
.pramboot_supported = false,
.hid_supported = true,
.upgrade = fts_ft5452_upgrade,
};
#define FTS_DELAY_ERASE_PAGE_2K 80
#define FTS_SIZE_PAGE_2K 2048
/************************************************************************
* Name: fts_ft5652_upgrade
* Brief:
* Input:
* Output:
* Return: return 0 if success, otherwise return error code
**********************************************************************/
static int fts_ft5652_upgrade(u8 *buf, u32 len)
{
int ret = 0;
u32 start_addr = 0;
u8 cmd[4] = { 0 };
u32 delay = 0;
int ecc_in_host = 0;
int ecc_in_tp = 0;
if ((buf == NULL) || (len < FTS_MIN_LEN)) {
FTS_ERROR("buffer/len(%x) is invalid", len);
return -EINVAL;
}
/* enter into upgrade environment */
ret = fts_fwupg_enter_into_boot();
if (ret < 0) {
FTS_ERROR("enter into pramboot/bootloader fail,ret=%d", ret);
goto fw_reset;
}
cmd[0] = FTS_CMD_APP_DATA_LEN_INCELL;
cmd[1] = BYTE_OFF_16(len);
cmd[2] = BYTE_OFF_8(len);
cmd[3] = BYTE_OFF_0(len);
ret = fts_write(cmd, FTS_CMD_DATA_LEN_LEN);
if (ret < 0) {
FTS_ERROR("data len cmd write fail");
goto fw_reset;
}
cmd[0] = FTS_CMD_FLASH_MODE;
cmd[1] = FLASH_MODE_UPGRADE_VALUE;
ret = fts_write(cmd, 2);
if (ret < 0) {
FTS_ERROR("upgrade mode(09) cmd write fail");
goto fw_reset;
}
delay = FTS_DELAY_ERASE_PAGE_2K * (len / FTS_SIZE_PAGE_2K);
ret = fts_fwupg_erase(delay);
if (ret < 0) {
FTS_ERROR("erase cmd write fail");
goto fw_reset;
}
/* write app */
start_addr = upgrade_func_ft5652.appoff;
ecc_in_host = fts_flash_write_buf(start_addr, buf, len, 1);
if (ecc_in_host < 0) {
FTS_ERROR("flash write fail");
goto fw_reset;
}
/* ecc */
ecc_in_tp = fts_fwupg_ecc_cal(start_addr, len);
if (ecc_in_tp < 0) {
FTS_ERROR("ecc read fail");
goto fw_reset;
}
FTS_INFO("ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host);
if (ecc_in_tp != ecc_in_host) {
FTS_ERROR("ecc check fail");
goto fw_reset;
}
FTS_INFO("upgrade success, reset to normal boot");
ret = fts_fwupg_reset_in_boot();
if (ret < 0)
FTS_ERROR("reset to normal boot fail");
msleep(200);
return 0;
fw_reset:
FTS_INFO("upgrade fail, reset to normal boot");
ret = fts_fwupg_reset_in_boot();
if (ret < 0)
FTS_ERROR("reset to normal boot fail");
return -EIO;
}
struct upgrade_func upgrade_func_ft5652 = {
.ctype = {0x88},
.fwveroff = 0x010E,
.fwcfgoff = 0x1F80,
.appoff = 0x0000,
.upgspec_version = UPGRADE_SPEC_V_1_0,
.pramboot_supported = false,
.hid_supported = true,
.upgrade = fts_ft5652_upgrade,
};

View File

@@ -0,0 +1,477 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, Focaltech Ltd. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_gestrue.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-08
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "focaltech_core.h"
/******************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define KEY_GESTURE_U KEY_U
#define KEY_GESTURE_UP KEY_UP
#define KEY_GESTURE_DOWN KEY_DOWN
#define KEY_GESTURE_LEFT KEY_LEFT
#define KEY_GESTURE_RIGHT KEY_RIGHT
#define KEY_GESTURE_O KEY_O
#define KEY_GESTURE_E KEY_E
#define KEY_GESTURE_M KEY_M
#define KEY_GESTURE_L KEY_L
#define KEY_GESTURE_W KEY_W
#define KEY_GESTURE_S KEY_S
#define KEY_GESTURE_V KEY_V
#define KEY_GESTURE_C KEY_C
#define KEY_GESTURE_Z KEY_Z
#define GESTURE_LEFT 0x20
#define GESTURE_RIGHT 0x21
#define GESTURE_UP 0x22
#define GESTURE_DOWN 0x23
#define GESTURE_DOUBLECLICK 0x24
#define GESTURE_O 0x30
#define GESTURE_W 0x31
#define GESTURE_M 0x32
#define GESTURE_E 0x33
#define GESTURE_L 0x44
#define GESTURE_S 0x46
#define GESTURE_V 0x54
#define GESTURE_Z 0x41
#define GESTURE_C 0x34
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/*
* gesture_id - mean which gesture is recognised
* point_num - points number of this gesture
* coordinate_x - All gesture point x coordinate
* coordinate_y - All gesture point y coordinate
* mode - gesture enable/disable, need enable by host
* - 1:enable gesture function(default) 0:disable
* active - gesture work flag,
* always set 1 when suspend, set 0 when resume
*/
struct fts_gesture_st {
u8 gesture_id;
u8 point_num;
u16 coordinate_x[FTS_GESTURE_POINTS_MAX];
u16 coordinate_y[FTS_GESTURE_POINTS_MAX];
};
/*****************************************************************************
* Static variables
*****************************************************************************/
static struct fts_gesture_st fts_gesture_data;
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
static ssize_t fts_gesture_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
u8 val = 0;
struct fts_ts_data *ts_data = fts_data;
mutex_lock(&ts_data->input_dev->mutex);
fts_read_reg(FTS_REG_GESTURE_EN, &val);
count = snprintf(buf, PAGE_SIZE, "Gesture Mode:%s\n",
ts_data->gesture_mode ? "On" : "Off");
count += snprintf(buf + count, PAGE_SIZE, "Reg(0xD0)=%d\n", val);
mutex_unlock(&ts_data->input_dev->mutex);
return count;
}
static ssize_t fts_gesture_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct fts_ts_data *ts_data = fts_data;
mutex_lock(&ts_data->input_dev->mutex);
if (FTS_SYSFS_ECHO_ON(buf)) {
FTS_DEBUG("enable gesture");
ts_data->gesture_mode = ENABLE;
} else if (FTS_SYSFS_ECHO_OFF(buf)) {
FTS_DEBUG("disable gesture");
ts_data->gesture_mode = DISABLE;
}
mutex_unlock(&ts_data->input_dev->mutex);
return count;
}
static ssize_t fts_gesture_buf_show(
struct device *dev, struct device_attribute *attr, char *buf)
{
int count = 0;
int i = 0;
struct input_dev *input_dev = fts_data->input_dev;
struct fts_gesture_st *gesture = &fts_gesture_data;
mutex_lock(&input_dev->mutex);
count = snprintf(buf, PAGE_SIZE, "Gesture ID:%d\n", gesture->gesture_id);
count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum:%d\n",
gesture->point_num);
count += snprintf(buf + count, PAGE_SIZE, "Gesture Points Buffer:\n");
/* save point data,max:6 */
for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) {
count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i,
gesture->coordinate_x[i], gesture->coordinate_y[i]);
if ((i + 1) % 4 == 0)
count += snprintf(buf + count, PAGE_SIZE, "\n");
}
count += snprintf(buf + count, PAGE_SIZE, "\n");
mutex_unlock(&input_dev->mutex);
return count;
}
static ssize_t fts_gesture_buf_store(
struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
return -EPERM;
}
/* sysfs gesture node
* read example: cat fts_gesture_mode ---read gesture mode
* write example:echo 1 > fts_gesture_mode --- write gesture mode to 1
*
*/
static DEVICE_ATTR(fts_gesture_mode, S_IRUGO | S_IWUSR, fts_gesture_show,
fts_gesture_store);
/*
* read example: cat fts_gesture_buf --- read gesture buf
*/
static DEVICE_ATTR(fts_gesture_buf, S_IRUGO | S_IWUSR,
fts_gesture_buf_show, fts_gesture_buf_store);
static struct attribute *fts_gesture_mode_attrs[] = {
&dev_attr_fts_gesture_mode.attr,
&dev_attr_fts_gesture_buf.attr,
NULL,
};
static struct attribute_group fts_gesture_group = {
.attrs = fts_gesture_mode_attrs,
};
static int fts_create_gesture_sysfs(struct device *dev)
{
int ret = 0;
ret = sysfs_create_group(&dev->kobj, &fts_gesture_group);
if (ret) {
FTS_ERROR("gesture sys node create fail");
sysfs_remove_group(&dev->kobj, &fts_gesture_group);
return ret;
}
return 0;
}
static void fts_gesture_report(struct input_dev *input_dev, int gesture_id)
{
int gesture;
FTS_DEBUG("gesture_id:0x%x", gesture_id);
switch (gesture_id) {
case GESTURE_LEFT:
gesture = KEY_GESTURE_LEFT;
break;
case GESTURE_RIGHT:
gesture = KEY_GESTURE_RIGHT;
break;
case GESTURE_UP:
gesture = KEY_GESTURE_UP;
break;
case GESTURE_DOWN:
gesture = KEY_GESTURE_DOWN;
break;
case GESTURE_DOUBLECLICK:
gesture = KEY_POWER;
break;
case GESTURE_O:
gesture = KEY_GESTURE_O;
break;
case GESTURE_W:
gesture = KEY_GESTURE_W;
break;
case GESTURE_M:
gesture = KEY_GESTURE_M;
break;
case GESTURE_E:
gesture = KEY_GESTURE_E;
break;
case GESTURE_L:
gesture = KEY_GESTURE_L;
break;
case GESTURE_S:
gesture = KEY_GESTURE_S;
break;
case GESTURE_V:
gesture = KEY_GESTURE_V;
break;
case GESTURE_Z:
gesture = KEY_GESTURE_Z;
break;
case GESTURE_C:
gesture = KEY_GESTURE_C;
break;
default:
gesture = -1;
break;
}
/* report event key */
if (gesture != -1) {
FTS_DEBUG("Gesture Code=%d", gesture);
input_report_key(input_dev, gesture, 1);
input_sync(input_dev);
input_report_key(input_dev, gesture, 0);
input_sync(input_dev);
}
}
/*****************************************************************************
* Name: fts_gesture_readdata
* Brief: Read information about gesture: enable flag/gesture points..., if ges-
* ture enable, save gesture points' information, and report to OS.
* It will be called this function every intrrupt when FTS_GESTURE_EN = 1
*
* gesture data length: 1(enable) + 1(reserve) + 2(header) + 6 * 4
* Input: ts_data - global struct data
* data - gesture data buffer if non-flash, else NULL
* Output:
* Return: 0 - read gesture data successfully, the report data is gesture data
* 1 - tp not in suspend/gesture not enable in TP FW
* -Exx - error
*****************************************************************************/
int fts_gesture_readdata(struct fts_ts_data *ts_data, u8 *data)
{
int ret = 0;
int i = 0;
int index = 0;
u8 buf[FTS_GESTURE_DATA_LEN] = { 0 };
struct input_dev *input_dev = ts_data->input_dev;
struct fts_gesture_st *gesture = &fts_gesture_data;
if (!ts_data->suspended || !ts_data->gesture_mode) {
return 1;
}
ret = fts_read_reg(FTS_REG_GESTURE_EN, &buf[0]);
if ((ret < 0) || (buf[0] != ENABLE)) {
FTS_DEBUG("gesture not enable in fw, don't process gesture");
return 1;
}
buf[2] = FTS_REG_GESTURE_OUTPUT_ADDRESS;
ret = fts_read(&buf[2], 1, &buf[2], FTS_GESTURE_DATA_LEN - 2);
if (ret < 0) {
FTS_ERROR("read gesture header data fail");
return ret;
}
/* init variable before read gesture point */
memset(gesture->coordinate_x, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16));
memset(gesture->coordinate_y, 0, FTS_GESTURE_POINTS_MAX * sizeof(u16));
gesture->gesture_id = buf[2];
gesture->point_num = buf[3];
FTS_DEBUG("gesture_id=%d, point_num=%d",
gesture->gesture_id, gesture->point_num);
/* save point data,max:6 */
for (i = 0; i < FTS_GESTURE_POINTS_MAX; i++) {
index = 4 * i + 4;
gesture->coordinate_x[i] = (u16)(((buf[0 + index] & 0x0F) << 8)
+ buf[1 + index]);
gesture->coordinate_y[i] = (u16)(((buf[2 + index] & 0x0F) << 8)
+ buf[3 + index]);
}
/* report gesture to OS */
fts_gesture_report(input_dev, gesture->gesture_id);
return 0;
}
void fts_gesture_recovery(struct fts_ts_data *ts_data)
{
if (ts_data->gesture_mode && ts_data->suspended) {
FTS_DEBUG("gesture recovery...");
fts_write_reg(0xD1, 0xFF);
fts_write_reg(0xD2, 0xFF);
fts_write_reg(0xD5, 0xFF);
fts_write_reg(0xD6, 0xFF);
fts_write_reg(0xD7, 0xFF);
fts_write_reg(0xD8, 0xFF);
fts_write_reg(FTS_REG_GESTURE_EN, ENABLE);
}
}
int fts_gesture_suspend(struct fts_ts_data *ts_data)
{
int i = 0;
u8 state = 0xFF;
FTS_FUNC_ENTER();
if (enable_irq_wake(ts_data->irq)) {
FTS_DEBUG("enable_irq_wake(irq:%d) fail", ts_data->irq);
}
for (i = 0; i < 5; i++) {
fts_write_reg(0xD1, 0xFF);
fts_write_reg(0xD2, 0xFF);
fts_write_reg(0xD5, 0xFF);
fts_write_reg(0xD6, 0xFF);
fts_write_reg(0xD7, 0xFF);
fts_write_reg(0xD8, 0xFF);
fts_write_reg(FTS_REG_GESTURE_EN, ENABLE);
msleep(1);
fts_read_reg(FTS_REG_GESTURE_EN, &state);
if (state == ENABLE)
break;
}
if (i >= 5)
FTS_ERROR("make IC enter into gesture(suspend) fail,state:%x", state);
else
FTS_INFO("Enter into gesture(suspend) successfully");
FTS_FUNC_EXIT();
return 0;
}
int fts_gesture_resume(struct fts_ts_data *ts_data)
{
int i = 0;
u8 state = 0xFF;
FTS_FUNC_ENTER();
if (disable_irq_wake(ts_data->irq)) {
FTS_DEBUG("disable_irq_wake(irq:%d) fail", ts_data->irq);
}
for (i = 0; i < 5; i++) {
fts_write_reg(FTS_REG_GESTURE_EN, DISABLE);
msleep(1);
fts_read_reg(FTS_REG_GESTURE_EN, &state);
if (state == DISABLE)
break;
}
if (i >= 5)
FTS_ERROR("make IC exit gesture(resume) fail,state:%x", state);
else
FTS_INFO("resume from gesture successfully");
FTS_FUNC_EXIT();
return 0;
}
int fts_gesture_init(struct fts_ts_data *ts_data)
{
struct input_dev *input_dev = ts_data->input_dev;
FTS_FUNC_ENTER();
input_set_capability(input_dev, EV_KEY, KEY_POWER);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C);
__set_bit(KEY_GESTURE_RIGHT, input_dev->keybit);
__set_bit(KEY_GESTURE_LEFT, input_dev->keybit);
__set_bit(KEY_GESTURE_UP, input_dev->keybit);
__set_bit(KEY_GESTURE_DOWN, input_dev->keybit);
__set_bit(KEY_GESTURE_U, input_dev->keybit);
__set_bit(KEY_GESTURE_O, input_dev->keybit);
__set_bit(KEY_GESTURE_E, input_dev->keybit);
__set_bit(KEY_GESTURE_M, input_dev->keybit);
__set_bit(KEY_GESTURE_W, input_dev->keybit);
__set_bit(KEY_GESTURE_L, input_dev->keybit);
__set_bit(KEY_GESTURE_S, input_dev->keybit);
__set_bit(KEY_GESTURE_V, input_dev->keybit);
__set_bit(KEY_GESTURE_C, input_dev->keybit);
__set_bit(KEY_GESTURE_Z, input_dev->keybit);
fts_create_gesture_sysfs(ts_data->dev);
memset(&fts_gesture_data, 0, sizeof(struct fts_gesture_st));
ts_data->gesture_mode = FTS_GESTURE_EN;
FTS_FUNC_EXIT();
return 0;
}
int fts_gesture_exit(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
sysfs_remove_group(&ts_data->dev->kobj, &fts_gesture_group);
FTS_FUNC_EXIT();
return 0;
}

View File

@@ -0,0 +1,548 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, FocalTech Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/************************************************************************
*
* File Name: focaltech_i2c.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-08-04
*
* Abstract: i2c communication with TP
*
* Version: v1.0
*
* Revision History:
*
************************************************************************/
/*****************************************************************************
* Included header files
*****************************************************************************/
#include "focaltech_core.h"
#include <linux/pm_runtime.h>
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define I2C_RETRY_NUMBER 3
#define I2C_BUF_LENGTH 256
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/*****************************************************************************
* Static variables
*****************************************************************************/
static struct fts_ts_data *ts_data;
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
/*****************************************************************************
* functions body
*****************************************************************************/
static int fts_i2c_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret = 0;
int i = 0;
struct i2c_msg msg_list[2];
struct i2c_msg *msg = NULL;
int msg_num = 0;
/* must have data when read */
if (!ts_data || !ts_data->client || !data || !datalen
|| (datalen >= I2C_BUF_LENGTH) || (cmdlen >= I2C_BUF_LENGTH)) {
FTS_ERROR("fts_data/client/cmdlen(%d)/data/datalen(%d) is invalid",
cmdlen, datalen);
return -EINVAL;
}
mutex_lock(&ts_data->bus_lock);
memset(&msg_list[0], 0, sizeof(struct i2c_msg));
memset(&msg_list[1], 0, sizeof(struct i2c_msg));
memcpy(ts_data->bus_tx_buf, cmd, cmdlen);
msg_list[0].addr = ts_data->client->addr;
msg_list[0].flags = 0;
msg_list[0].len = cmdlen;
msg_list[0].buf = ts_data->bus_tx_buf;
msg_list[1].addr = ts_data->client->addr;
msg_list[1].flags = I2C_M_RD;
msg_list[1].len = datalen;
msg_list[1].buf = ts_data->bus_rx_buf;
if (cmd && cmdlen) {
msg = &msg_list[0];
msg_num = 2;
} else {
msg = &msg_list[1];
msg_num = 1;
}
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(ts_data->client->adapter, msg, msg_num);
if (ret < 0) {
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
if (atomic_read(&ts_data->trusted_touch_enabled) &&
ret == -ECONNRESET) {
pr_err("failed i2c read reacquiring session\n");
pm_runtime_put_sync(
ts_data->client->adapter->dev.parent);
pm_runtime_get_sync(
ts_data->client->adapter->dev.parent);
}
#endif
#endif
FTS_ERROR("i2c_transfer(read) fail,ret:%d", ret);
} else {
memcpy(data, ts_data->bus_rx_buf, datalen);
break;
}
}
if (ret < 0) {
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
pr_err("initiating abort due to i2c xfer failure\n");
fts_ts_trusted_touch_tvm_i2c_failure_report(ts_data);
#endif
#endif
}
mutex_unlock(&ts_data->bus_lock);
return ret;
}
static int fts_i2c_write(u8 *writebuf, u32 writelen)
{
int ret = 0;
int i = 0;
struct i2c_msg msgs;
if (!ts_data || !ts_data->client || !writebuf || !writelen
|| (writelen >= I2C_BUF_LENGTH)) {
FTS_ERROR("fts_data/client/data/datalen(%d) is invalid", writelen);
return -EINVAL;
}
mutex_lock(&ts_data->bus_lock);
memset(&msgs, 0, sizeof(struct i2c_msg));
memcpy(ts_data->bus_tx_buf, writebuf, writelen);
msgs.addr = ts_data->client->addr;
msgs.flags = 0;
msgs.len = writelen;
msgs.buf = ts_data->bus_tx_buf;
for (i = 0; i < I2C_RETRY_NUMBER; i++) {
ret = i2c_transfer(ts_data->client->adapter, &msgs, 1);
if (ret < 0) {
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
if (atomic_read(&ts_data->trusted_touch_enabled) &&
ret == -ECONNRESET){
pr_err("failed i2c write reacquiring session\n");
pm_runtime_put_sync(
ts_data->client->adapter->dev.parent);
pm_runtime_get_sync(
ts_data->client->adapter->dev.parent);
}
#endif
#endif
FTS_ERROR("i2c_transfer(write) fail,ret:%d", ret);
} else {
break;
}
}
if (ret < 0) {
#ifdef CONFIG_FTS_TRUSTED_TOUCH
#ifdef CONFIG_ARCH_QTI_VM
pr_err("initiating abort due to i2c xfer failure\n");
fts_ts_trusted_touch_tvm_i2c_failure_report(ts_data);
#endif
#endif
}
mutex_unlock(&ts_data->bus_lock);
return ret;
}
static int fts_i2c_init(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
ts_data->bus_tx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL);
if (ts_data->bus_tx_buf == NULL) {
FTS_ERROR("failed to allocate memory for bus_tx_buf");
return -ENOMEM;
}
ts_data->bus_rx_buf = kzalloc(I2C_BUF_LENGTH, GFP_KERNEL);
if (ts_data->bus_rx_buf == NULL) {
FTS_ERROR("failed to allocate memory for bus_rx_buf");
return -ENOMEM;
}
FTS_FUNC_EXIT();
return 0;
}
static int fts_i2c_exit(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
if (ts_data && ts_data->bus_tx_buf) {
kfree(ts_data->bus_tx_buf);
ts_data->bus_tx_buf = NULL;
}
if (ts_data && ts_data->bus_rx_buf) {
kfree(ts_data->bus_rx_buf);
ts_data->bus_rx_buf = NULL;
}
FTS_FUNC_EXIT();
return 0;
}
/*****************************************************************************
* Private constant and macro definitions using #define
****************************************************************************/
#define SPI_RETRY_NUMBER 3
#define CS_HIGH_DELAY 150 /* unit: us */
#define SPI_BUF_LENGTH 256
#define DATA_CRC_EN 0x20
#define WRITE_CMD 0x00
#define READ_CMD (0x80 | DATA_CRC_EN)
#define SPI_DUMMY_BYTE 3
#define SPI_HEADER_LENGTH 6 /*CRC*/
/*****************************************************************************
* functions body
****************************************************************************/
/* spi interface */
static int fts_spi_transfer(u8 *tx_buf, u8 *rx_buf, u32 len)
{
int ret = 0;
struct spi_device *spi = fts_data->spi;
struct spi_message msg;
struct spi_transfer xfer = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = len,
};
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
ret = spi_sync(spi, &msg);
if (ret) {
FTS_ERROR("spi_sync fail,ret:%d", ret);
return ret;
}
return ret;
}
static void crckermit(u8 *data, u32 len, u16 *crc_out)
{
u32 i = 0;
u32 j = 0;
u16 crc = 0xFFFF;
for (i = 0; i < len; i++) {
crc ^= data[i];
for (j = 0; j < 8; j++) {
if (crc & 0x01)
crc = (crc >> 1) ^ 0x8408;
else
crc = (crc >> 1);
}
}
*crc_out = crc;
}
static int rdata_check(u8 *rdata, u32 rlen)
{
u16 crc_calc = 0;
u16 crc_read = 0;
crckermit(rdata, rlen - 2, &crc_calc);
crc_read = (u16)(rdata[rlen - 1] << 8) + rdata[rlen - 2];
if (crc_calc != crc_read)
return -EIO;
return 0;
}
static int fts_spi_write(u8 *writebuf, u32 writelen)
{
int ret = 0;
int i = 0;
struct fts_ts_data *ts_data = fts_data;
u8 *txbuf = NULL;
u8 *rxbuf = NULL;
u32 txlen = 0;
u32 txlen_need = writelen + SPI_HEADER_LENGTH + ts_data->dummy_byte;
u32 datalen = writelen - 1;
if (!writebuf || !writelen) {
FTS_ERROR("writebuf/len is invalid");
return -EINVAL;
}
mutex_lock(&ts_data->bus_lock);
if (txlen_need > SPI_BUF_LENGTH) {
txbuf = kzalloc(txlen_need, GFP_KERNEL);
if (txbuf == NULL) {
FTS_ERROR("txbuf malloc fail");
ret = -ENOMEM;
goto err_write;
}
rxbuf = kzalloc(txlen_need, GFP_KERNEL);
if (rxbuf == NULL) {
FTS_ERROR("rxbuf malloc fail");
ret = -ENOMEM;
goto err_write;
}
} else {
txbuf = ts_data->bus_tx_buf;
rxbuf = ts_data->bus_rx_buf;
memset(txbuf, 0x0, SPI_BUF_LENGTH);
memset(rxbuf, 0x0, SPI_BUF_LENGTH);
}
txbuf[txlen++] = writebuf[0];
txbuf[txlen++] = WRITE_CMD;
txbuf[txlen++] = (datalen >> 8) & 0xFF;
txbuf[txlen++] = datalen & 0xFF;
if (datalen > 0) {
txlen = txlen + SPI_DUMMY_BYTE;
memcpy(&txbuf[txlen], &writebuf[1], datalen);
txlen = txlen + datalen;
}
for (i = 0; i < SPI_RETRY_NUMBER; i++) {
ret = fts_spi_transfer(txbuf, rxbuf, txlen);
if ((ret == 0) && ((rxbuf[3] & 0xA0) == 0))
break;
FTS_DEBUG("data write(addr:%x),status:%x,retry:%d,ret:%d",
writebuf[0], rxbuf[3], i, ret);
ret = -EIO;
udelay(CS_HIGH_DELAY);
}
if (ret < 0) {
FTS_ERROR("data write(addr:%x) fail,status:%x,ret:%d",
writebuf[0], rxbuf[3], ret);
}
err_write:
if (txlen_need > SPI_BUF_LENGTH) {
kfree(txbuf);
kfree(rxbuf);
}
udelay(CS_HIGH_DELAY);
mutex_unlock(&ts_data->bus_lock);
return ret;
}
static int fts_spi_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret = 0;
int i = 0;
u8 *txbuf = NULL;
u8 *rxbuf = NULL;
u32 txlen = 0;
u32 txlen_need = datalen + SPI_HEADER_LENGTH + ts_data->dummy_byte;
u8 ctrl = READ_CMD;
u32 dp = 0;
if (!cmd || !cmdlen || !data || !datalen) {
FTS_ERROR("cmd/cmdlen/data/datalen is invalid");
return -EINVAL;
}
mutex_lock(&ts_data->bus_lock);
if (txlen_need > SPI_BUF_LENGTH) {
txbuf = kzalloc(txlen_need, GFP_KERNEL);
if (txbuf == NULL) {
FTS_ERROR("txbuf malloc fail");
ret = -ENOMEM;
goto err_read;
}
rxbuf = kzalloc(txlen_need, GFP_KERNEL);
if (rxbuf == NULL) {
FTS_ERROR("rxbuf malloc fail");
ret = -ENOMEM;
goto err_read;
}
} else {
txbuf = ts_data->bus_tx_buf;
rxbuf = ts_data->bus_rx_buf;
memset(txbuf, 0x0, SPI_BUF_LENGTH);
memset(rxbuf, 0x0, SPI_BUF_LENGTH);
}
txbuf[txlen++] = cmd[0];
txbuf[txlen++] = ctrl;
txbuf[txlen++] = (datalen >> 8) & 0xFF;
txbuf[txlen++] = datalen & 0xFF;
dp = txlen + SPI_DUMMY_BYTE;
txlen = dp + datalen;
if (ctrl & DATA_CRC_EN)
txlen = txlen + 2;
for (i = 0; i < SPI_RETRY_NUMBER; i++) {
ret = fts_spi_transfer(txbuf, rxbuf, txlen);
if ((ret == 0) && ((rxbuf[3] & 0xA0) == 0)) {
memcpy(data, &rxbuf[dp], datalen);
/* crc check */
if (ctrl & DATA_CRC_EN) {
ret = rdata_check(&rxbuf[dp], txlen - dp);
if (ret < 0) {
FTS_DEBUG("data read(addr:%x) crc abnormal,retry:%d",
cmd[0], i);
udelay(CS_HIGH_DELAY);
continue;
}
}
break;
}
FTS_DEBUG("data read(addr:%x) status:%x,retry:%d,ret:%d",
cmd[0], rxbuf[3], i, ret);
ret = -EIO;
udelay(CS_HIGH_DELAY);
}
if (ret < 0) {
FTS_ERROR("data read(addr:%x) %s,status:%x,ret:%d", cmd[0],
(i >= SPI_RETRY_NUMBER) ? "crc abnormal" : "fail",
rxbuf[3], ret);
}
err_read:
if (txlen_need > SPI_BUF_LENGTH) {
kfree(txbuf);
kfree(rxbuf);
}
udelay(CS_HIGH_DELAY);
mutex_unlock(&ts_data->bus_lock);
return ret;
}
static int fts_spi_init(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
ts_data->bus_tx_buf = kzalloc(SPI_BUF_LENGTH, GFP_KERNEL);
if (ts_data->bus_tx_buf == NULL) {
FTS_ERROR("failed to allocate memory for bus_tx_buf");
return -ENOMEM;
}
ts_data->bus_rx_buf = kzalloc(SPI_BUF_LENGTH, GFP_KERNEL);
if (ts_data->bus_rx_buf == NULL) {
FTS_ERROR("failed to allocate memory for bus_rx_buf");
return -ENOMEM;
}
ts_data->dummy_byte = SPI_DUMMY_BYTE;
FTS_FUNC_EXIT();
return 0;
}
static int fts_spi_exit(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
if (ts_data && ts_data->bus_tx_buf) {
kfree(ts_data->bus_tx_buf);
ts_data->bus_tx_buf = NULL;
}
if (ts_data && ts_data->bus_rx_buf) {
kfree(ts_data->bus_rx_buf);
ts_data->bus_rx_buf = NULL;
}
FTS_FUNC_EXIT();
return 0;
}
int fts_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret = 0;
if (ts_data->bus_type == BUS_TYPE_I2C)
ret = fts_i2c_read(cmd, cmdlen, data, datalen);
else
ret = fts_spi_read(cmd, cmdlen, data, datalen);
return ret;
}
int fts_write(u8 *writebuf, u32 writelen)
{
int ret = 0;
if (ts_data->bus_type == BUS_TYPE_I2C)
ret = fts_i2c_write(writebuf, writelen);
else
ret = fts_spi_write(writebuf, writelen);
return ret;
}
int fts_read_reg(u8 addr, u8 *value)
{
return fts_read(&addr, 1, value, 1);
}
int fts_write_reg(u8 addr, u8 value)
{
u8 buf[2] = { 0 };
buf[0] = addr;
buf[1] = value;
return fts_write(buf, sizeof(buf));
}
int fts_bus_init(struct fts_ts_data *_ts_data)
{
ts_data = _ts_data;
if (ts_data->bus_type == BUS_TYPE_I2C)
return fts_i2c_init(ts_data);
return fts_spi_init(ts_data);
}
int fts_bus_exit(struct fts_ts_data *ts_data)
{
if (ts_data->bus_type == BUS_TYPE_I2C)
return fts_i2c_exit(ts_data);
return fts_spi_exit(ts_data);
}

View File

@@ -0,0 +1,135 @@
/*
*
* FocalTech TouchScreen driver.
*
* Copyright (c) 2012-2019, FocalTech Systems, Ltd., all rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*****************************************************************************
*
* File Name: focaltech_point_report_check.c
*
* Author: Focaltech Driver Team
*
* Created: 2016-11-16
*
* Abstract: point report check function
*
* Version: v1.0
*
* Revision History:
*
*****************************************************************************/
/*****************************************************************************
* Included header files
*****************************************************************************/
#include "focaltech_core.h"
#if FTS_POINT_REPORT_CHECK_EN
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define POINT_REPORT_CHECK_WAIT_TIME 200 /* unit:ms */
/*****************************************************************************
* functions body
*****************************************************************************/
/*****************************************************************************
* Name: fts_prc_func
* Brief: fts point report check work func, report whole up of points
* Input:
* Output:
* Return:
*****************************************************************************/
static void fts_prc_func(struct work_struct *work)
{
struct fts_ts_data *ts_data = container_of(work,
struct fts_ts_data, prc_work.work);
struct input_dev *input_dev = ts_data->input_dev;
#if FTS_MT_PROTOCOL_B_EN
u32 finger_count = 0;
u32 max_touches = fts_data->pdata->max_touch_number;
#endif
FTS_FUNC_ENTER();
mutex_lock(&ts_data->report_mutex);
#if FTS_MT_PROTOCOL_B_EN
for (finger_count = 0; finger_count < max_touches; finger_count++) {
input_mt_slot(input_dev, finger_count);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
}
#else
input_mt_sync(input_dev);
#endif
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
mutex_unlock(&ts_data->report_mutex);
FTS_FUNC_EXIT();
}
/*****************************************************************************
* Name: fts_prc_queue_work
* Brief: fts point report check queue work, call it when interrupt comes
* Input:
* Output:
* Return:
*****************************************************************************/
void fts_prc_queue_work(struct fts_ts_data *ts_data)
{
cancel_delayed_work_sync(&ts_data->prc_work);
queue_delayed_work(ts_data->ts_workqueue, &ts_data->prc_work,
msecs_to_jiffies(POINT_REPORT_CHECK_WAIT_TIME));
}
/*****************************************************************************
* Name: fts_point_report_check_init
* Brief:
* Input:
* Output:
* Return: < 0: Fail to create esd check queue
*****************************************************************************/
int fts_point_report_check_init(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
if (ts_data->ts_workqueue) {
INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);
} else {
FTS_ERROR("fts workqueue is NULL, can't run point report check function");
return -EINVAL;
}
FTS_FUNC_EXIT();
return 0;
}
/*****************************************************************************
* Name: fts_point_report_check_exit
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
int fts_point_report_check_exit(struct fts_ts_data *ts_data)
{
FTS_FUNC_ENTER();
FTS_FUNC_EXIT();
return 0;
}
#endif /* FTS_POINT_REPORT_CHECK_EN */

4601
nt36xxx/nt36xxx.c Normal file

File diff suppressed because it is too large Load Diff

386
nt36xxx/nt36xxx.h Normal file
View File

@@ -0,0 +1,386 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 - 2018 Novatek, Inc.
*
* $Revision: 47247 $
* $Date: 2019-07-10 10:41:36 +0800 (Wed, 10 Jul 2019) $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef _LINUX_NVT_TOUCH_H
#define _LINUX_NVT_TOUCH_H
#if !defined(NVT_NT36XXX_SPI) /* NT36XXX I2C */
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include "nt36xxx_mem_map.h"
#define NVT_DEBUG 1
//---GPIO number---
#define NVTTOUCH_RST_PIN 980
#define NVTTOUCH_INT_PIN 943
//---INT trigger mode---
//#define IRQ_TYPE_EDGE_RISING 1
//#define IRQ_TYPE_EDGE_FALLING 2
#define INT_TRIGGER_TYPE IRQ_TYPE_EDGE_RISING
//---I2C driver info.---
#define NVT_I2C_NAME "NVT-ts"
#define I2C_BLDR_Address 0x01
#define I2C_FW_Address 0x01
#define I2C_HW_Address 0x62
#if NVT_DEBUG
#define NVT_LOG(fmt, args...) pr_err("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args)
#else
#define NVT_LOG(fmt, args...) pr_info("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args)
#endif
#define NVT_ERR(fmt, args...) pr_err("[%s] %s %d: " fmt, NVT_I2C_NAME, __func__, __LINE__, ##args)
//---Input device info.---
#define NVT_TS_NAME "NVTCapacitiveTouchScreen"
//---Touch info.---
#define TOUCH_DEFAULT_MAX_WIDTH 1080
#define TOUCH_DEFAULT_MAX_HEIGHT 2408
#define TOUCH_MAX_FINGER_NUM 10
#define TOUCH_KEY_NUM 0
#if TOUCH_KEY_NUM > 0
extern const uint16_t touch_key_array[TOUCH_KEY_NUM];
#endif
#define TOUCH_FORCE_NUM 1000
/* Enable only when module have tp reset pin and connected to host */
#define NVT_TOUCH_SUPPORT_HW_RST 1
//---Customerized func.---
#define NVT_TOUCH_PROC 1
#define NVT_TOUCH_EXT_PROC 1
#define NVT_TOUCH_MP 1
#define MT_PROTOCOL_B 1
#define WAKEUP_GESTURE 0
#if WAKEUP_GESTURE
extern const uint16_t gesture_key_array[];
#endif
#define BOOT_UPDATE_FIRMWARE 1
#define BOOT_UPDATE_FIRMWARE_NAME "novatek_ts_fw.bin"
//---ESD Protect.---
#define NVT_TOUCH_ESD_PROTECT 0
#define NVT_TOUCH_ESD_CHECK_PERIOD 1500 /* ms */
struct nvt_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct delayed_work nvt_fwu_work;
uint16_t addr;
int8_t phys[32];
const struct i2c_device_id *id;
#if defined(CONFIG_DRM)
struct notifier_block drm_panel_notif;
#elif defined(_MSM_DRM_NOTIFY_H_)
struct notifier_block drm_notif;
#else
struct notifier_block fb_notif;
#endif
uint8_t fw_ver;
uint8_t x_num;
uint8_t y_num;
uint16_t abs_x_max;
uint16_t abs_y_max;
uint8_t max_touch_num;
uint8_t max_button_num;
uint32_t int_trigger_type;
int32_t irq_gpio;
uint32_t irq_flags;
int32_t reset_gpio;
uint32_t reset_flags;
struct mutex lock;
const struct nvt_ts_mem_map *mmap;
uint8_t carrier_system;
uint16_t nvt_pid;
uint8_t xbuf[1025];
struct mutex xbuf_lock;
bool irq_enabled;
void *notifier_cookie;
};
#if NVT_TOUCH_PROC
struct nvt_flash_data{
rwlock_t lock;
struct i2c_client *client;
};
#endif
typedef enum {
RESET_STATE_INIT = 0xA0,// IC reset
RESET_STATE_REK, // ReK baseline
RESET_STATE_REK_FINISH, // baseline is ready
RESET_STATE_NORMAL_RUN, // normal run
RESET_STATE_MAX = 0xAF
} RST_COMPLETE_STATE;
typedef enum {
EVENT_MAP_HOST_CMD = 0x50,
EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE = 0x51,
EVENT_MAP_RESET_COMPLETE = 0x60,
EVENT_MAP_FWINFO = 0x78,
EVENT_MAP_PROJECTID = 0x9A,
} I2C_EVENT_MAP;
//---extern structures---
extern struct nvt_ts_data *ts;
//---extern functions---
extern int32_t CTP_I2C_READ(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len);
extern int32_t CTP_I2C_WRITE(struct i2c_client *client, uint16_t address, uint8_t *buf, uint16_t len);
extern void nvt_bootloader_reset(void);
extern void nvt_sw_reset_idle(void);
extern int32_t nvt_check_fw_reset_state(RST_COMPLETE_STATE check_reset_state);
extern int32_t nvt_get_fw_info(void);
extern int32_t nvt_clear_fw_status(void);
extern int32_t nvt_check_fw_status(void);
extern int32_t nvt_set_page(uint16_t i2c_addr, uint32_t addr);
#if NVT_TOUCH_ESD_PROTECT
extern void nvt_esd_check_enable(uint8_t enable);
#endif /* #if NVT_TOUCH_ESD_PROTECT */
extern void nvt_stop_crc_reboot(void);
#else /* NT36XXX_SPI */
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>
#include "nt36xxx_mem_map.h"
#define NVT_SPI_DEBUG 0
//---GPIO number---
#define NVTTOUCH_RST_PIN 980
#define NVTTOUCH_INT_PIN 943
//---INT trigger mode---
//#define NVT_SPI_IRQ_TYPE_EDGE_RISING 1
//#define NVT_SPI_IRQ_TYPE_EDGE_FALLING 2
#define NVT_SPI_INT_TRIGGER_TYPE IRQ_TYPE_EDGE_RISING
//---SPI driver info.---
#define NVT_SPI_NAME "NVT-SPI"
#if NVT_SPI_DEBUG
#define NVT_LOG(fmt, args...) pr_err("[%s] %s %d: " fmt, "NVT-SPI", __func__, __LINE__, ##args)
#else
#define NVT_LOG(fmt, args...) pr_debug("[%s] %s %d: " fmt, "NVT-SPI", __func__, __LINE__, ##args)
#endif
#define NVT_ERR(fmt, args...) pr_err("[%s] %s %d: " fmt, "NVT-SPI", __func__, __LINE__, ##args)
//---Input device info.---
#define NVT_SPI_TS_NAME "NVTCapacitiveTouchScreen"
#define NVT_SPI_PEN_NAME "NVTCapacitivePen"
//---Touch info.---
#define NVT_SPI_TOUCH_DEFAULT_MAX_WIDTH 1080
#define NVT_SPI_TOUCH_DEFAULT_MAX_HEIGHT 2400
#define NVT_SPI_TOUCH_MAX_FINGER_NUM 10
#define NVT_SPI_TOUCH_KEY_NUM 0
#if NVT_SPI_TOUCH_KEY_NUM > 0
extern const uint16_t nvt_spi_touch_key_array[NVT_SPI_TOUCH_KEY_NUM];
#endif
#define NVT_SPI_TOUCH_FORCE_NUM 1000
//---for Pen---
#define NVT_SPI_PEN_PRESSURE_MAX (4095)
#define NVT_SPI_PEN_DISTANCE_MAX (1)
#define NVT_SPI_PEN_TILT_MIN (-60)
#define NVT_SPI_PEN_TILT_MAX (60)
/* Enable only when module have tp reset pin and connected to host */
#define NVT_SPI_TOUCH_SUPPORT_HW_RST 0
//---Customerized func.---
#define NVT_SPI_TOUCH_PROC 1
#define NVT_SPI_TOUCH_EXT_PROC 1
#define NVT_SPI_TOUCH_MP 0
#define NVT_SPI_MT_PROTOCOL_B 1
#define NVT_SPI_WAKEUP_GESTURE 0
#if NVT_SPI_WAKEUP_GESTURE
extern const uint16_t nvt_spi_gesture_key_array[];
#endif
#define NVT_SPI_BOOT_UPDATE_FIRMWARE 1
#define NVT_SPI_BOOT_UPDATE_FIRMWARE_NAME "novatek_spi_fw.bin"
#define NVT_SPI_MP_UPDATE_FIRMWARE_NAME "novatek_ts_mp.bin"
#define NVT_SPI_POINT_DATA_CHECKSUM 1
#define NVT_SPI_POINT_DATA_CHECKSUM_LEN 65
//---ESD Protect.---
#define NVT_SPI_TOUCH_ESD_PROTECT 0
#define NVT_SPI_TOUCH_ESD_CHECK_PERIOD 1500 /* ms */
#define NVT_SPI_TOUCH_WDT_RECOVERY 1
#define NVT_SPI_CHECK_PEN_DATA_CHECKSUM 0
struct nvt_spi_data_t {
struct spi_device *client;
struct input_dev *input_dev;
struct delayed_work nvt_fwu_work;
uint16_t addr;
int8_t phys[32];
#if defined(CONFIG_DRM)
struct notifier_block drm_panel_notif;
#elif defined(_MSM_DRM_NOTIFY_H_)
struct notifier_block drm_notif;
#else
struct notifier_block fb_notif;
#endif
uint8_t fw_ver;
uint8_t x_num;
uint8_t y_num;
uint16_t abs_x_max;
uint16_t abs_y_max;
uint8_t max_touch_num;
uint8_t max_button_num;
uint32_t int_trigger_type;
int32_t irq_gpio;
uint32_t irq_flags;
int32_t reset_gpio;
uint32_t reset_flags;
struct mutex lock;
const struct nvt_spi_mem_map *mmap;
uint8_t hw_crc;
uint16_t nvt_pid;
uint8_t *rbuf;
uint8_t *xbuf;
struct mutex xbuf_lock;
bool irq_enabled;
bool pen_support;
bool wgp_stylus;
uint8_t x_gang_num;
uint8_t y_gang_num;
struct input_dev *pen_input_dev;
int8_t pen_phys[32];
void *notifier_cookie;
const char *touch_environment;
#ifdef CONFIG_NOVATEK_SPI_TRUSTED_TOUCH
struct trusted_touch_vm_info *vm_info;
struct mutex fts_clk_io_ctrl_mutex;
struct completion trusted_touch_powerdown;
struct clk *core_clk;
struct clk *iface_clk;
atomic_t trusted_touch_initialized;
atomic_t trusted_touch_enabled;
atomic_t trusted_touch_underway;
atomic_t trusted_touch_event;
atomic_t trusted_touch_abort_status;
atomic_t delayed_vm_probe_pending;
atomic_t trusted_touch_mode;
#endif
};
#if NVT_SPI_TOUCH_PROC
struct nvt_spi_flash_data {
rwlock_t lock;
};
#endif
enum NVT_SPI_RST_COMPLETE_STATE {
NVT_SPI_RESET_STATE_INIT = 0xA0,// IC reset
NVT_SPI_RESET_STATE_REK, // ReK baseline
NVT_SPI_RESET_STATE_REK_FINISH, // baseline is ready
NVT_SPI_RESET_STATE_NORMAL_RUN, // normal run
NVT_SPI_RESET_STATE_MAX = 0xAF
};
enum NVT_SPI_EVENT_MAP {
NVT_SPI_EVENT_MAP_HOST_CMD = 0x50,
NVT_SPI_EVENT_MAP_HANDSHAKING_or_SUB_CMD_BYTE = 0x51,
NVT_SPI_EVENT_MAP_RESET_COMPLETE = 0x60,
NVT_SPI_EVENT_MAP_FWINFO = 0x78,
NVT_SPI_EVENT_MAP_PROJECTID = 0x9A,
};
//---SPI READ/WRITE---
#define NVT_SPI_WRITE_MASK(a) (a | 0x80)
#define NVT_SPI_READ_MASK(a) (a & 0x7F)
#define NVT_SPI_DUMMY_BYTES (1)
#define NVT_SPI_TRANSFER_LEN (63*1024)
#define NVT_SPI_READ_LEN (2*1024)
#define NVT_SPI_XBUF_LEN (NVT_SPI_TRANSFER_LEN+1+NVT_SPI_DUMMY_BYTES)
enum NVT_SPI_RW {
NVT_SPI_WRITE = 0,
NVT_SPI_READ = 1
};
//---extern structures---
extern struct nvt_spi_data_t *nvt_spi_data;
//---extern functions---
int32_t nvt_spi_read(uint8_t *buf, uint16_t len);
int32_t nvt_spi_write(uint8_t *buf, uint16_t len);
void nvt_spi_bootloader_reset(void);
void nvt_spi_eng_reset(void);
void nvt_spi_sw_reset(void);
void nvt_spi_sw_reset_idle(void);
void nvt_spi_boot_ready(void);
void nvt_spi_bld_crc_enable(void);
void nvt_spi_fw_crc_enable(void);
void nvt_spi_tx_auto_copy_mode(void);
int32_t nvt_spi_update_firmware(char *firmware_name);
void nvt_spi_update_firmware_work(struct work_struct *work);
int32_t nvt_spi_check_fw_reset_state(enum NVT_SPI_RST_COMPLETE_STATE reset_state);
int32_t nvt_spi_get_fw_info(void);
int32_t nvt_spi_clear_fw_status(void);
int32_t nvt_spi_check_fw_status(void);
int32_t nvt_spi_check_spi_dma_tx_info(void);
int32_t nvt_spi_set_page(uint32_t addr);
int32_t nvt_spi_write_addr(uint32_t addr, uint8_t data);
#if NVT_SPI_TOUCH_EXT_PROC
int32_t nvt_spi_extra_proc_init(void);
void nvt_spi_extra_proc_deinit(void);
#endif
#if NVT_SPI_TOUCH_MP
extern int32_t nvt_spi_mp_proc_init(void);
extern void nvt_spi_mp_proc_deinit(void);
#endif
#if NVT_SPI_TOUCH_ESD_PROTECT
extern void nvt_spi_esd_check_enable(uint8_t enable);
#endif /* #if NVT_SPI_TOUCH_ESD_PROTECT */
#endif
#endif /* _LINUX_NVT_TOUCH_H */

1537
nt36xxx/nt36xxx_ext_proc.c Normal file

File diff suppressed because it is too large Load Diff

2002
nt36xxx/nt36xxx_fw_update.c Normal file

File diff suppressed because it is too large Load Diff

607
nt36xxx/nt36xxx_mem_map.h Normal file
View File

@@ -0,0 +1,607 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 - 2018 Novatek, Inc.
*
* $Revision: 48764 $
* $Date: 2019-08-08 14:52:12 +0800 (Thu, 08 Aug 2019) $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#define CHIP_VER_TRIM_ADDR 0x3F004
#define CHIP_VER_TRIM_OLD_ADDR 0x1F64E
#if !defined(NVT_NT36XXX_SPI) /* NT36XXX I2C */
struct nvt_ts_mem_map {
uint32_t EVENT_BUF_ADDR;
uint32_t RAW_PIPE0_ADDR;
uint32_t RAW_PIPE1_ADDR;
uint32_t BASELINE_ADDR;
uint32_t BASELINE_BTN_ADDR;
uint32_t DIFF_PIPE0_ADDR;
uint32_t DIFF_PIPE1_ADDR;
uint32_t RAW_BTN_PIPE0_ADDR;
uint32_t RAW_BTN_PIPE1_ADDR;
uint32_t DIFF_BTN_PIPE0_ADDR;
uint32_t DIFF_BTN_PIPE1_ADDR;
uint32_t READ_FLASH_CHECKSUM_ADDR;
uint32_t RW_FLASH_DATA_ADDR;
};
struct nvt_ts_hw_info {
uint8_t carrier_system;
uint8_t hw_crc;
};
static const struct nvt_ts_mem_map NT36526_memory_map = {
.EVENT_BUF_ADDR = 0x22D00,
.RAW_PIPE0_ADDR = 0x24000,
.RAW_PIPE1_ADDR = 0x24000,
.BASELINE_ADDR = 0x21758,
.BASELINE_BTN_ADDR = 0,
.DIFF_PIPE0_ADDR = 0x20AB0,
.DIFF_PIPE1_ADDR = 0x24AB0,
.RAW_BTN_PIPE0_ADDR = 0,
.RAW_BTN_PIPE1_ADDR = 0,
.DIFF_BTN_PIPE0_ADDR = 0,
.DIFF_BTN_PIPE1_ADDR = 0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
};
static const struct nvt_ts_mem_map NT36675_memory_map = {
.EVENT_BUF_ADDR = 0x22D00,
.RAW_PIPE0_ADDR = 0x24000,
.RAW_PIPE1_ADDR = 0x24000,
.BASELINE_ADDR = 0x21B90,
.BASELINE_BTN_ADDR = 0,
.DIFF_PIPE0_ADDR = 0x20C60,
.DIFF_PIPE1_ADDR = 0x24C60,
.RAW_BTN_PIPE0_ADDR = 0,
.RAW_BTN_PIPE1_ADDR = 0,
.DIFF_BTN_PIPE0_ADDR = 0,
.DIFF_BTN_PIPE1_ADDR = 0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
};
static const struct nvt_ts_mem_map NT36672A_memory_map = {
.EVENT_BUF_ADDR = 0x21C00,
.RAW_PIPE0_ADDR = 0x20000,
.RAW_PIPE1_ADDR = 0x23000,
.BASELINE_ADDR = 0x20BFC,
.BASELINE_BTN_ADDR = 0x23BFC,
.DIFF_PIPE0_ADDR = 0x206DC,
.DIFF_PIPE1_ADDR = 0x236DC,
.RAW_BTN_PIPE0_ADDR = 0x20510,
.RAW_BTN_PIPE1_ADDR = 0x23510,
.DIFF_BTN_PIPE0_ADDR = 0x20BF0,
.DIFF_BTN_PIPE1_ADDR = 0x23BF0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
};
static const struct nvt_ts_mem_map NT36772_memory_map = {
.EVENT_BUF_ADDR = 0x11E00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10E70,
.BASELINE_BTN_ADDR = 0x12E70,
.DIFF_PIPE0_ADDR = 0x10830,
.DIFF_PIPE1_ADDR = 0x12830,
.RAW_BTN_PIPE0_ADDR = 0x10E60,
.RAW_BTN_PIPE1_ADDR = 0x12E60,
.DIFF_BTN_PIPE0_ADDR = 0x10E68,
.DIFF_BTN_PIPE1_ADDR = 0x12E68,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
};
static const struct nvt_ts_mem_map NT36525_memory_map = {
.EVENT_BUF_ADDR = 0x11A00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10B08,
.BASELINE_BTN_ADDR = 0x12B08,
.DIFF_PIPE0_ADDR = 0x1064C,
.DIFF_PIPE1_ADDR = 0x1264C,
.RAW_BTN_PIPE0_ADDR = 0x10634,
.RAW_BTN_PIPE1_ADDR = 0x12634,
.DIFF_BTN_PIPE0_ADDR = 0x10AFC,
.DIFF_BTN_PIPE1_ADDR = 0x12AFC,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
};
static const struct nvt_ts_mem_map NT36676F_memory_map = {
.EVENT_BUF_ADDR = 0x11A00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10B08,
.BASELINE_BTN_ADDR = 0x12B08,
.DIFF_PIPE0_ADDR = 0x1064C,
.DIFF_PIPE1_ADDR = 0x1264C,
.RAW_BTN_PIPE0_ADDR = 0x10634,
.RAW_BTN_PIPE1_ADDR = 0x12634,
.DIFF_BTN_PIPE0_ADDR = 0x10AFC,
.DIFF_BTN_PIPE1_ADDR = 0x12AFC,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
};
static struct nvt_ts_hw_info NT36526_hw_info = {
.carrier_system = 2,
.hw_crc = 2,
};
static struct nvt_ts_hw_info NT36675_hw_info = {
.carrier_system = 2,
.hw_crc = 2,
};
static struct nvt_ts_hw_info NT36672A_hw_info = {
.carrier_system = 0,
.hw_crc = 1,
};
static struct nvt_ts_hw_info NT36772_hw_info = {
.carrier_system = 0,
.hw_crc = 0,
};
static struct nvt_ts_hw_info NT36525_hw_info = {
.carrier_system = 0,
.hw_crc = 0,
};
static struct nvt_ts_hw_info NT36676F_hw_info = {
.carrier_system = 0,
.hw_crc = 0,
};
#define NVT_ID_BYTE_MAX 6
struct nvt_ts_trim_id_table {
uint8_t id[NVT_ID_BYTE_MAX];
uint8_t mask[NVT_ID_BYTE_MAX];
const struct nvt_ts_mem_map *mmap;
const struct nvt_ts_hw_info *hwinfo;
};
static const struct nvt_ts_trim_id_table trim_id_table[] = {
{.id = {0x20, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x00, 0xFF, 0xFF, 0x80, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x0C, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0E, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x0C, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x26, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36526_memory_map, .hwinfo = &NT36526_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x75, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x82, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x82, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x67, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0x55, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xAA, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xAA, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x72, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x70, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36525_memory_map, .hwinfo = &NT36525_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36676F_memory_map, .hwinfo = &NT36676F_hw_info}
};
#else /* NT36XXX_SPI */
#define NVT_SPI_CHIP_VER_TRIM_ADDR 0x3F004
#define NVT_SPI_CHIP_VER_TRIM_OLD_ADDR 0x1F64E
struct nvt_spi_mem_map {
uint32_t EVENT_BUF_ADDR;
uint32_t RAW_PIPE0_ADDR;
uint32_t RAW_PIPE1_ADDR;
uint32_t BASELINE_ADDR;
uint32_t BASELINE_BTN_ADDR;
uint32_t DIFF_PIPE0_ADDR;
uint32_t DIFF_PIPE1_ADDR;
uint32_t RAW_BTN_PIPE0_ADDR;
uint32_t RAW_BTN_PIPE1_ADDR;
uint32_t DIFF_BTN_PIPE0_ADDR;
uint32_t DIFF_BTN_PIPE1_ADDR;
uint32_t PEN_2D_BL_TIP_X_ADDR;
uint32_t PEN_2D_BL_TIP_Y_ADDR;
uint32_t PEN_2D_BL_RING_X_ADDR;
uint32_t PEN_2D_BL_RING_Y_ADDR;
uint32_t PEN_2D_DIFF_TIP_X_ADDR;
uint32_t PEN_2D_DIFF_TIP_Y_ADDR;
uint32_t PEN_2D_DIFF_RING_X_ADDR;
uint32_t PEN_2D_DIFF_RING_Y_ADDR;
uint32_t PEN_2D_RAW_TIP_X_ADDR;
uint32_t PEN_2D_RAW_TIP_Y_ADDR;
uint32_t PEN_2D_RAW_RING_X_ADDR;
uint32_t PEN_2D_RAW_RING_Y_ADDR;
uint32_t PEN_1D_DIFF_TIP_X_ADDR;
uint32_t PEN_1D_DIFF_TIP_Y_ADDR;
uint32_t PEN_1D_DIFF_RING_X_ADDR;
uint32_t PEN_1D_DIFF_RING_Y_ADDR;
uint32_t READ_FLASH_CHECKSUM_ADDR;
uint32_t RW_FLASH_DATA_ADDR;
/* Phase 2 Host Download */
uint32_t BOOT_RDY_ADDR;
uint32_t POR_CD_ADDR;
uint32_t TX_AUTO_COPY_EN;
uint32_t SPI_DMA_TX_INFO;
/* BLD CRC */
uint32_t BLD_LENGTH_ADDR;
uint32_t ILM_LENGTH_ADDR;
uint32_t DLM_LENGTH_ADDR;
uint32_t BLD_DES_ADDR;
uint32_t ILM_DES_ADDR;
uint32_t DLM_DES_ADDR;
uint32_t G_ILM_CHECKSUM_ADDR;
uint32_t G_DLM_CHECKSUM_ADDR;
uint32_t R_ILM_CHECKSUM_ADDR;
uint32_t R_DLM_CHECKSUM_ADDR;
uint32_t BLD_CRC_EN_ADDR;
uint32_t DMA_CRC_EN_ADDR;
uint32_t BLD_ILM_DLM_CRC_ADDR;
uint32_t DMA_CRC_FLAG_ADDR;
};
struct nvt_spi_hw_info {
uint8_t hw_crc;
};
static const struct nvt_spi_mem_map NT36523_memory_map = {
.EVENT_BUF_ADDR = 0x2FE00,
.RAW_PIPE0_ADDR = 0x30FA0,
.RAW_PIPE1_ADDR = 0x30FA0,
.BASELINE_ADDR = 0x36510,
.BASELINE_BTN_ADDR = 0,
.DIFF_PIPE0_ADDR = 0x373E8,
.DIFF_PIPE1_ADDR = 0x38068,
.RAW_BTN_PIPE0_ADDR = 0,
.RAW_BTN_PIPE1_ADDR = 0,
.DIFF_BTN_PIPE0_ADDR = 0,
.DIFF_BTN_PIPE1_ADDR = 0,
.PEN_2D_BL_TIP_X_ADDR = 0x2988A,
.PEN_2D_BL_TIP_Y_ADDR = 0x29A1A,
.PEN_2D_BL_RING_X_ADDR = 0x29BAA,
.PEN_2D_BL_RING_Y_ADDR = 0x29D3A,
.PEN_2D_DIFF_TIP_X_ADDR = 0x29ECA,
.PEN_2D_DIFF_TIP_Y_ADDR = 0x2A05A,
.PEN_2D_DIFF_RING_X_ADDR = 0x2A1EA,
.PEN_2D_DIFF_RING_Y_ADDR = 0x2A37A,
.PEN_2D_RAW_TIP_X_ADDR = 0x2A50A,
.PEN_2D_RAW_TIP_Y_ADDR = 0x2A69A,
.PEN_2D_RAW_RING_X_ADDR = 0x2A82A,
.PEN_2D_RAW_RING_Y_ADDR = 0x2A9BA,
.PEN_1D_DIFF_TIP_X_ADDR = 0x2AB4A,
.PEN_1D_DIFF_TIP_Y_ADDR = 0x2ABAE,
.PEN_1D_DIFF_RING_X_ADDR = 0x2AC12,
.PEN_1D_DIFF_RING_Y_ADDR = 0x2AC76,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x3F10D,
.TX_AUTO_COPY_EN = 0x3F7E8,
.SPI_DMA_TX_INFO = 0x3F7F1,
/* BLD CRC */
.BLD_LENGTH_ADDR = 0x3F138, //0x3F138 ~ 0x3F13A (3 bytes)
.ILM_LENGTH_ADDR = 0x3F118, //0x3F118 ~ 0x3F11A (3 bytes)
.DLM_LENGTH_ADDR = 0x3F130, //0x3F130 ~ 0x3F132 (3 bytes)
.BLD_DES_ADDR = 0x3F114, //0x3F114 ~ 0x3F116 (3 bytes)
.ILM_DES_ADDR = 0x3F128, //0x3F128 ~ 0x3F12A (3 bytes)
.DLM_DES_ADDR = 0x3F12C, //0x3F12C ~ 0x3F12E (3 bytes)
.G_ILM_CHECKSUM_ADDR = 0x3F100, //0x3F100 ~ 0x3F103 (4 bytes)
.G_DLM_CHECKSUM_ADDR = 0x3F104, //0x3F104 ~ 0x3F107 (4 bytes)
.R_ILM_CHECKSUM_ADDR = 0x3F120, //0x3F120 ~ 0x3F123 (4 bytes)
.R_DLM_CHECKSUM_ADDR = 0x3F124, //0x3F124 ~ 0x3F127 (4 bytes)
.BLD_CRC_EN_ADDR = 0x3F30E,
.DMA_CRC_EN_ADDR = 0x3F136,
.BLD_ILM_DLM_CRC_ADDR = 0x3F133,
.DMA_CRC_FLAG_ADDR = 0x3F134,
};
static const struct nvt_spi_mem_map NT36526_memory_map = {
.EVENT_BUF_ADDR = 0x22D00,
.RAW_PIPE0_ADDR = 0x24000,
.RAW_PIPE1_ADDR = 0x24000,
.BASELINE_ADDR = 0x21758,
.BASELINE_BTN_ADDR = 0,
.DIFF_PIPE0_ADDR = 0x20AB0,
.DIFF_PIPE1_ADDR = 0x24AB0,
.RAW_BTN_PIPE0_ADDR = 0,
.RAW_BTN_PIPE1_ADDR = 0,
.DIFF_BTN_PIPE0_ADDR = 0,
.DIFF_BTN_PIPE1_ADDR = 0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x3F10D,
/* BLD CRC */
.BLD_LENGTH_ADDR = 0x3F138, //0x3F138 ~ 0x3F13A (3 bytes)
.ILM_LENGTH_ADDR = 0x3F118, //0x3F118 ~ 0x3F11A (3 bytes)
.DLM_LENGTH_ADDR = 0x3F130, //0x3F130 ~ 0x3F132 (3 bytes)
.BLD_DES_ADDR = 0x3F114, //0x3F114 ~ 0x3F116 (3 bytes)
.ILM_DES_ADDR = 0x3F128, //0x3F128 ~ 0x3F12A (3 bytes)
.DLM_DES_ADDR = 0x3F12C, //0x3F12C ~ 0x3F12E (3 bytes)
.G_ILM_CHECKSUM_ADDR = 0x3F100, //0x3F100 ~ 0x3F103 (4 bytes)
.G_DLM_CHECKSUM_ADDR = 0x3F104, //0x3F104 ~ 0x3F107 (4 bytes)
.R_ILM_CHECKSUM_ADDR = 0x3F120, //0x3F120 ~ 0x3F123 (4 bytes)
.R_DLM_CHECKSUM_ADDR = 0x3F124, //0x3F124 ~ 0x3F127 (4 bytes)
.BLD_CRC_EN_ADDR = 0x3F30E,
.DMA_CRC_EN_ADDR = 0x3F136,
.BLD_ILM_DLM_CRC_ADDR = 0x3F133,
.DMA_CRC_FLAG_ADDR = 0x3F134,
};
static const struct nvt_spi_mem_map NT36675_memory_map = {
.EVENT_BUF_ADDR = 0x22D00,
.RAW_PIPE0_ADDR = 0x24000,
.RAW_PIPE1_ADDR = 0x24000,
.BASELINE_ADDR = 0x21B90,
.BASELINE_BTN_ADDR = 0,
.DIFF_PIPE0_ADDR = 0x20C60,
.DIFF_PIPE1_ADDR = 0x24C60,
.RAW_BTN_PIPE0_ADDR = 0,
.RAW_BTN_PIPE1_ADDR = 0,
.DIFF_BTN_PIPE0_ADDR = 0,
.DIFF_BTN_PIPE1_ADDR = 0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x3F10D,
/* BLD CRC */
.BLD_LENGTH_ADDR = 0x3F138, //0x3F138 ~ 0x3F13A (3 bytes)
.ILM_LENGTH_ADDR = 0x3F118, //0x3F118 ~ 0x3F11A (3 bytes)
.DLM_LENGTH_ADDR = 0x3F130, //0x3F130 ~ 0x3F132 (3 bytes)
.BLD_DES_ADDR = 0x3F114, //0x3F114 ~ 0x3F116 (3 bytes)
.ILM_DES_ADDR = 0x3F128, //0x3F128 ~ 0x3F12A (3 bytes)
.DLM_DES_ADDR = 0x3F12C, //0x3F12C ~ 0x3F12E (3 bytes)
.G_ILM_CHECKSUM_ADDR = 0x3F100, //0x3F100 ~ 0x3F103 (4 bytes)
.G_DLM_CHECKSUM_ADDR = 0x3F104, //0x3F104 ~ 0x3F107 (4 bytes)
.R_ILM_CHECKSUM_ADDR = 0x3F120, //0x3F120 ~ 0x3F123 (4 bytes)
.R_DLM_CHECKSUM_ADDR = 0x3F124, //0x3F124 ~ 0x3F127 (4 bytes)
.BLD_CRC_EN_ADDR = 0x3F30E,
.DMA_CRC_EN_ADDR = 0x3F136,
.BLD_ILM_DLM_CRC_ADDR = 0x3F133,
.DMA_CRC_FLAG_ADDR = 0x3F134,
};
static const struct nvt_spi_mem_map NT36672A_memory_map = {
.EVENT_BUF_ADDR = 0x21C00,
.RAW_PIPE0_ADDR = 0x20000,
.RAW_PIPE1_ADDR = 0x23000,
.BASELINE_ADDR = 0x20BFC,
.BASELINE_BTN_ADDR = 0x23BFC,
.DIFF_PIPE0_ADDR = 0x206DC,
.DIFF_PIPE1_ADDR = 0x236DC,
.RAW_BTN_PIPE0_ADDR = 0x20510,
.RAW_BTN_PIPE1_ADDR = 0x23510,
.DIFF_BTN_PIPE0_ADDR = 0x20BF0,
.DIFF_BTN_PIPE1_ADDR = 0x23BF0,
.READ_FLASH_CHECKSUM_ADDR = 0x24000,
.RW_FLASH_DATA_ADDR = 0x24002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x3F10D,
/* BLD CRC */
.BLD_LENGTH_ADDR = 0x3F10E, //0x3F10E ~ 0x3F10F (2 bytes)
.ILM_LENGTH_ADDR = 0x3F118, //0x3F118 ~ 0x3F119 (2 bytes)
.DLM_LENGTH_ADDR = 0x3F130, //0x3F130 ~ 0x3F131 (2 bytes)
.BLD_DES_ADDR = 0x3F114, //0x3F114 ~ 0x3F116 (3 bytes)
.ILM_DES_ADDR = 0x3F128, //0x3F128 ~ 0x3F12A (3 bytes)
.DLM_DES_ADDR = 0x3F12C, //0x3F12C ~ 0x3F12E (3 bytes)
.G_ILM_CHECKSUM_ADDR = 0x3F100, //0x3F100 ~ 0x3F103 (4 bytes)
.G_DLM_CHECKSUM_ADDR = 0x3F104, //0x3F104 ~ 0x3F107 (4 bytes)
.R_ILM_CHECKSUM_ADDR = 0x3F120, //0x3F120 ~ 0x3F123 (4 bytes)
.R_DLM_CHECKSUM_ADDR = 0x3F124, //0x3F124 ~ 0x3F127 (4 bytes)
.BLD_CRC_EN_ADDR = 0x3F30E,
.DMA_CRC_EN_ADDR = 0x3F132,
.BLD_ILM_DLM_CRC_ADDR = 0x3F133,
.DMA_CRC_FLAG_ADDR = 0x3F134,
};
static const struct nvt_spi_mem_map NT36772_memory_map = {
.EVENT_BUF_ADDR = 0x11E00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10E70,
.BASELINE_BTN_ADDR = 0x12E70,
.DIFF_PIPE0_ADDR = 0x10830,
.DIFF_PIPE1_ADDR = 0x12830,
.RAW_BTN_PIPE0_ADDR = 0x10E60,
.RAW_BTN_PIPE1_ADDR = 0x12E60,
.DIFF_BTN_PIPE0_ADDR = 0x10E68,
.DIFF_BTN_PIPE1_ADDR = 0x12E68,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x1F141,
.POR_CD_ADDR = 0x1F61C,
/* BLD CRC */
.R_ILM_CHECKSUM_ADDR = 0x1BF00,
};
static const struct nvt_spi_mem_map NT36525_memory_map = {
.EVENT_BUF_ADDR = 0x11A00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10B08,
.BASELINE_BTN_ADDR = 0x12B08,
.DIFF_PIPE0_ADDR = 0x1064C,
.DIFF_PIPE1_ADDR = 0x1264C,
.RAW_BTN_PIPE0_ADDR = 0x10634,
.RAW_BTN_PIPE1_ADDR = 0x12634,
.DIFF_BTN_PIPE0_ADDR = 0x10AFC,
.DIFF_BTN_PIPE1_ADDR = 0x12AFC,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
/* Phase 2 Host Download */
.BOOT_RDY_ADDR = 0x1F141,
.POR_CD_ADDR = 0x1F61C,
/* BLD CRC */
.R_ILM_CHECKSUM_ADDR = 0x1BF00,
};
static const struct nvt_spi_mem_map NT36676F_memory_map = {
.EVENT_BUF_ADDR = 0x11A00,
.RAW_PIPE0_ADDR = 0x10000,
.RAW_PIPE1_ADDR = 0x12000,
.BASELINE_ADDR = 0x10B08,
.BASELINE_BTN_ADDR = 0x12B08,
.DIFF_PIPE0_ADDR = 0x1064C,
.DIFF_PIPE1_ADDR = 0x1264C,
.RAW_BTN_PIPE0_ADDR = 0x10634,
.RAW_BTN_PIPE1_ADDR = 0x12634,
.DIFF_BTN_PIPE0_ADDR = 0x10AFC,
.DIFF_BTN_PIPE1_ADDR = 0x12AFC,
.READ_FLASH_CHECKSUM_ADDR = 0x14000,
.RW_FLASH_DATA_ADDR = 0x14002,
};
static struct nvt_spi_hw_info NT36523_hw_info = {
.hw_crc = 2,
};
static struct nvt_spi_hw_info NT36526_hw_info = {
.hw_crc = 2,
};
static struct nvt_spi_hw_info NT36675_hw_info = {
.hw_crc = 2,
};
static struct nvt_spi_hw_info NT36672A_hw_info = {
.hw_crc = 1,
};
static struct nvt_spi_hw_info NT36772_hw_info = {
.hw_crc = 0,
};
static struct nvt_spi_hw_info NT36525_hw_info = {
.hw_crc = 0,
};
static struct nvt_spi_hw_info NT36676F_hw_info = {
.hw_crc = 0,
};
#define NVT_SPI_ID_BYTE_MAX 6
struct nvt_spi_trim_id_table_t {
uint8_t id[NVT_SPI_ID_BYTE_MAX];
uint8_t mask[NVT_SPI_ID_BYTE_MAX];
const struct nvt_spi_mem_map *mmap;
const struct nvt_spi_hw_info *hwinfo;
};
static const struct nvt_spi_trim_id_table_t nvt_spi_trim_id_table[] = {
{.id = {0x0D, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x20, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x00, 0xFF, 0xFF, 0x80, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x0C, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0E, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x20, 0xFF, 0xFF, 0x23, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36523_memory_map, .hwinfo = &NT36523_hw_info},
{.id = {0x0C, 0xFF, 0xFF, 0x23, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36523_memory_map, .hwinfo = &NT36523_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x23, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36523_memory_map, .hwinfo = &NT36523_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x23, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36523_memory_map, .hwinfo = &NT36523_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x23, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36523_memory_map, .hwinfo = &NT36523_hw_info},
{.id = {0x0C, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x26, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36526_memory_map, .hwinfo = &NT36526_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x75, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36675_memory_map, .hwinfo = &NT36675_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x82, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x65, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x82, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0B, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x0A, 0xFF, 0xFF, 0x72, 0x67, 0x03}, .mask = {1, 0, 0, 1, 1, 1},
.mmap = &NT36672A_memory_map, .hwinfo = &NT36672A_hw_info},
{.id = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0x55, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xAA, 0x00, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xAA, 0x72, 0xFF, 0x00, 0x00, 0x00}, .mask = {1, 1, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x72, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x70, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x70, 0x67, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x72, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36772_memory_map, .hwinfo = &NT36772_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x25, 0x65, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36525_memory_map, .hwinfo = &NT36525_hw_info},
{.id = {0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x03}, .mask = {0, 0, 0, 1, 1, 1},
.mmap = &NT36676F_memory_map, .hwinfo = &NT36676F_hw_info}
};
#endif

1480
nt36xxx/nt36xxx_mp_ctrlram.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,460 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 - 2018 Novatek, Inc.
*
* $Revision: 46179 $
* $Date: 2019-06-14 13:47:17 +0800 (Fri, 14 Jun 2019) $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#if NVT_TOUCH_MP
static uint32_t IC_X_CFG_SIZE = 18;
static uint32_t IC_Y_CFG_SIZE = 36;
static uint32_t IC_KEY_CFG_SIZE = 4;
static uint32_t X_Channel = 18;
static uint32_t Y_Channel = 36;
static uint32_t Key_Channel = TOUCH_KEY_NUM;
static uint8_t AIN_X[40] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
static uint8_t AIN_Y[40] =
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
#if TOUCH_KEY_NUM > 0
static uint8_t AIN_KEY[8] = {0, 1, 2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
#endif /* #if TOUCH_KEY_NUM > 0 */
static int32_t PS_Config_Lmt_Short_Rawdata_P[40 * 40] = {
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,14008,
#if TOUCH_KEY_NUM > 0
14008,14008,14008,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_Short_Rawdata_N[40 * 40] = {
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,10000,
#if TOUCH_KEY_NUM > 0
10000,10000,10000,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_Open_Rawdata_P[40 * 40] = {
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,5120,
#if TOUCH_KEY_NUM > 0
5120,5120,5120,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_Open_Rawdata_N[40 * 40] = {
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,
#if TOUCH_KEY_NUM > 0
50,50,50,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_Rawdata_P[40 * 40] = {
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,
#if TOUCH_KEY_NUM > 0
2560,2560,2560,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_Rawdata_N[40 * 40] = {
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
#if TOUCH_KEY_NUM > 0
240,240,240,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_CC_P[40 * 40] = {
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,314,
#if TOUCH_KEY_NUM > 0
314,314,314,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_CC_N[40 * 40] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
#if TOUCH_KEY_NUM > 0
0,0,0,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_Diff_P[40 * 40] = {
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,
#if TOUCH_KEY_NUM > 0
75,75,75,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Lmt_FW_Diff_N[40 *40] = {
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,-75,
#if TOUCH_KEY_NUM > 0
-75,-75,-75,
#endif /* #if TOUCH_KEY_NUM > 0 */
};
static int32_t PS_Config_Diff_Test_Frame = 50;
#endif /* #if NVT_TOUCH_MP */

8
nt36xxx/nt36xxx_spi.c Normal file
View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define NVT_NT36XXX_SPI
#include "nt36xxx.c"

View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define NVT_NT36XXX_SPI
#include "nt36xxx_ext_proc.c"

View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define NVT_NT36XXX_SPI
#include "nt36xxx_fw_update.c"

6066
st/fts.c Normal file

File diff suppressed because it is too large Load Diff

396
st/fts.h Normal file
View File

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

153
st/fts_aoi_event.c Normal file
View File

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

1107
st/fts_driver_test.c Normal file

File diff suppressed because it is too large Load Diff

412
st/fts_gui.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

262
st/fts_lib/ftsError.c Normal file
View File

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

181
st/fts_lib/ftsError.h Normal file
View File

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

1178
st/fts_lib/ftsFlash.c Normal file

File diff suppressed because it is too large Load Diff

109
st/fts_lib/ftsFlash.h Normal file
View File

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

519
st/fts_lib/ftsFrame.c Normal file
View File

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

76
st/fts_lib/ftsFrame.h Normal file
View File

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

651
st/fts_lib/ftsGesture.c Normal file
View File

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

123
st/fts_lib/ftsGesture.h Normal file
View File

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

213
st/fts_lib/ftsHardware.h Normal file
View File

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

526
st/fts_lib/ftsIO.c Normal file
View File

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

64
st/fts_lib/ftsIO.h Normal file
View File

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

191
st/fts_lib/ftsSoftware.h Normal file
View File

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

3844
st/fts_lib/ftsTest.c Normal file

File diff suppressed because it is too large Load Diff

193
st/fts_lib/ftsTest.h Normal file
View File

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

109
st/fts_lib/ftsTime.c Normal file
View File

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

54
st/fts_lib/ftsTime.h Normal file
View File

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

1348
st/fts_lib/ftsTool.c Normal file

File diff suppressed because it is too large Load Diff

107
st/fts_lib/ftsTool.h Normal file
View File

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

View File

@@ -0,0 +1,606 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#define APEN_PHYS_NAME "synaptics_dsx/active_pen"
#define ACTIVE_PEN_MAX_PRESSURE_16BIT 65535
#define ACTIVE_PEN_MAX_PRESSURE_8BIT 255
struct synaptics_rmi4_f12_query_8 {
union {
struct {
unsigned char size_of_query9;
struct {
unsigned char data0_is_present:1;
unsigned char data1_is_present:1;
unsigned char data2_is_present:1;
unsigned char data3_is_present:1;
unsigned char data4_is_present:1;
unsigned char data5_is_present:1;
unsigned char data6_is_present:1;
unsigned char data7_is_present:1;
} __packed;
};
unsigned char data[2];
};
};
struct apen_data_8b_pressure {
union {
struct {
unsigned char status_pen:1;
unsigned char status_invert:1;
unsigned char status_barrel:1;
unsigned char status_reserved:5;
unsigned char x_lsb;
unsigned char x_msb;
unsigned char y_lsb;
unsigned char y_msb;
unsigned char pressure_msb;
unsigned char battery_state;
unsigned char pen_id_0_7;
unsigned char pen_id_8_15;
unsigned char pen_id_16_23;
unsigned char pen_id_24_31;
} __packed;
unsigned char data[11];
};
};
struct apen_data {
union {
struct {
unsigned char status_pen:1;
unsigned char status_invert:1;
unsigned char status_barrel:1;
unsigned char status_reserved:5;
unsigned char x_lsb;
unsigned char x_msb;
unsigned char y_lsb;
unsigned char y_msb;
unsigned char pressure_lsb;
unsigned char pressure_msb;
unsigned char battery_state;
unsigned char pen_id_0_7;
unsigned char pen_id_8_15;
unsigned char pen_id_16_23;
unsigned char pen_id_24_31;
} __packed;
unsigned char data[12];
};
};
struct synaptics_rmi4_apen_handle {
bool apen_present;
unsigned char intr_mask;
unsigned char battery_state;
unsigned short query_base_addr;
unsigned short control_base_addr;
unsigned short data_base_addr;
unsigned short command_base_addr;
unsigned short apen_data_addr;
unsigned short max_pressure;
unsigned int pen_id;
struct input_dev *apen_dev;
struct apen_data *apen_data;
struct synaptics_rmi4_data *rmi4_data;
};
static struct synaptics_rmi4_apen_handle *apen;
DECLARE_COMPLETION(apen_remove_complete);
static void apen_lift(void)
{
input_report_key(apen->apen_dev, BTN_TOUCH, 0);
input_report_key(apen->apen_dev, BTN_TOOL_PEN, 0);
input_report_key(apen->apen_dev, BTN_TOOL_RUBBER, 0);
input_sync(apen->apen_dev);
apen->apen_present = false;
}
static void apen_report(void)
{
int retval;
int x;
int y;
int pressure;
static int invert = -1;
struct apen_data_8b_pressure *apen_data_8b;
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
retval = synaptics_rmi4_reg_read(rmi4_data,
apen->apen_data_addr,
apen->apen_data->data,
sizeof(apen->apen_data->data));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read active pen data\n",
__func__);
return;
}
if (apen->apen_data->status_pen == 0) {
if (apen->apen_present)
apen_lift();
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: No active pen data\n",
__func__);
return;
}
x = (apen->apen_data->x_msb << 8) | (apen->apen_data->x_lsb);
y = (apen->apen_data->y_msb << 8) | (apen->apen_data->y_lsb);
if ((x == -1) && (y == -1)) {
if (apen->apen_present)
apen_lift();
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Active pen in range but no valid x & y\n",
__func__);
return;
}
if (!apen->apen_present)
invert = -1;
if (invert != -1 && invert != apen->apen_data->status_invert)
apen_lift();
invert = apen->apen_data->status_invert;
if (apen->max_pressure == ACTIVE_PEN_MAX_PRESSURE_16BIT) {
pressure = (apen->apen_data->pressure_msb << 8) |
apen->apen_data->pressure_lsb;
apen->battery_state = apen->apen_data->battery_state;
apen->pen_id = (apen->apen_data->pen_id_24_31 << 24) |
(apen->apen_data->pen_id_16_23 << 16) |
(apen->apen_data->pen_id_8_15 << 8) |
apen->apen_data->pen_id_0_7;
} else {
apen_data_8b = (struct apen_data_8b_pressure *)apen->apen_data;
pressure = apen_data_8b->pressure_msb;
apen->battery_state = apen_data_8b->battery_state;
apen->pen_id = (apen_data_8b->pen_id_24_31 << 24) |
(apen_data_8b->pen_id_16_23 << 16) |
(apen_data_8b->pen_id_8_15 << 8) |
apen_data_8b->pen_id_0_7;
}
input_report_key(apen->apen_dev, BTN_TOUCH, pressure > 0 ? 1 : 0);
input_report_key(apen->apen_dev,
apen->apen_data->status_invert > 0 ?
BTN_TOOL_RUBBER : BTN_TOOL_PEN, 1);
input_report_key(apen->apen_dev,
BTN_STYLUS, apen->apen_data->status_barrel > 0 ?
1 : 0);
input_report_abs(apen->apen_dev, ABS_X, x);
input_report_abs(apen->apen_dev, ABS_Y, y);
input_report_abs(apen->apen_dev, ABS_PRESSURE, pressure);
input_sync(apen->apen_dev);
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Active pen: status = %d, invert = %d, barrel = %d, x = %d, y = %d, pressure = %d\n",
__func__,
apen->apen_data->status_pen,
apen->apen_data->status_invert,
apen->apen_data->status_barrel,
x, y, pressure);
apen->apen_present = true;
}
static void apen_set_params(void)
{
input_set_abs_params(apen->apen_dev, ABS_X, 0,
apen->rmi4_data->sensor_max_x, 0, 0);
input_set_abs_params(apen->apen_dev, ABS_Y, 0,
apen->rmi4_data->sensor_max_y, 0, 0);
input_set_abs_params(apen->apen_dev, ABS_PRESSURE, 0,
apen->max_pressure, 0, 0);
}
static int apen_pressure(struct synaptics_rmi4_f12_query_8 *query_8)
{
int retval;
unsigned char ii;
unsigned char data_reg_presence;
unsigned char size_of_query_9;
unsigned char *query_9;
unsigned char *data_desc;
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
data_reg_presence = query_8->data[1];
size_of_query_9 = query_8->size_of_query9;
query_9 = kmalloc(size_of_query_9, GFP_KERNEL);
retval = synaptics_rmi4_reg_read(rmi4_data,
apen->query_base_addr + 9,
query_9,
size_of_query_9);
if (retval < 0)
goto exit;
data_desc = query_9;
for (ii = 0; ii < 6; ii++) {
if (!(data_reg_presence & (1 << ii)))
continue; /* The data register is not present */
data_desc++; /* Jump over the size entry */
while (*data_desc & (1 << 7))
data_desc++;
data_desc++; /* Go to the next descriptor */
}
data_desc++; /* Jump over the size entry */
/* Check for the presence of subpackets 1 and 2 */
if ((*data_desc & (3 << 1)) == (3 << 1))
apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_16BIT;
else
apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_8BIT;
exit:
kfree(query_9);
return retval;
}
static int apen_reg_init(void)
{
int retval;
unsigned char data_offset;
unsigned char size_of_query8;
struct synaptics_rmi4_f12_query_8 query_8;
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
retval = synaptics_rmi4_reg_read(rmi4_data,
apen->query_base_addr + 7,
&size_of_query8,
sizeof(size_of_query8));
if (retval < 0)
return retval;
retval = synaptics_rmi4_reg_read(rmi4_data,
apen->query_base_addr + 8,
query_8.data,
sizeof(query_8.data));
if (retval < 0)
return retval;
if ((size_of_query8 >= 2) && (query_8.data6_is_present)) {
data_offset = query_8.data0_is_present +
query_8.data1_is_present +
query_8.data2_is_present +
query_8.data3_is_present +
query_8.data4_is_present +
query_8.data5_is_present;
apen->apen_data_addr = apen->data_base_addr + data_offset;
retval = apen_pressure(&query_8);
if (retval < 0)
return retval;
} else {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Active pen support unavailable\n",
__func__);
retval = -ENODEV;
}
return retval;
}
static int apen_scan_pdt(void)
{
int retval;
unsigned char ii;
unsigned char page;
unsigned char intr_count = 0;
unsigned char intr_off;
unsigned char intr_src;
unsigned short addr;
struct synaptics_rmi4_fn_desc fd;
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
for (page = 0; page < PAGES_TO_SERVICE; page++) {
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
addr |= (page << 8);
retval = synaptics_rmi4_reg_read(rmi4_data,
addr,
(unsigned char *)&fd,
sizeof(fd));
if (retval < 0)
return retval;
addr &= ~(MASK_8BIT << 8);
if (fd.fn_number) {
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Found F%02x\n",
__func__, fd.fn_number);
switch (fd.fn_number) {
case SYNAPTICS_RMI4_F12:
goto f12_found;
}
} else {
break;
}
intr_count += fd.intr_src_count;
}
}
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to find F12\n",
__func__);
return -EINVAL;
f12_found:
apen->query_base_addr = fd.query_base_addr | (page << 8);
apen->control_base_addr = fd.ctrl_base_addr | (page << 8);
apen->data_base_addr = fd.data_base_addr | (page << 8);
apen->command_base_addr = fd.cmd_base_addr | (page << 8);
retval = apen_reg_init();
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to initialize active pen registers\n",
__func__);
return retval;
}
apen->intr_mask = 0;
intr_src = fd.intr_src_count;
intr_off = intr_count % 8;
for (ii = intr_off;
ii < (intr_src + intr_off);
ii++) {
apen->intr_mask |= 1 << ii;
}
rmi4_data->intr_mask[0] |= apen->intr_mask;
addr = rmi4_data->f01_ctrl_base_addr + 1;
retval = synaptics_rmi4_reg_write(rmi4_data,
addr,
&(rmi4_data->intr_mask[0]),
sizeof(rmi4_data->intr_mask[0]));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to set interrupt enable bit\n",
__func__);
return retval;
}
return 0;
}
static void synaptics_rmi4_apen_attn(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask)
{
if (!apen)
return;
if (apen->intr_mask & intr_mask)
apen_report();
return;
}
static int synaptics_rmi4_apen_init(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
if (apen) {
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Handle already exists\n",
__func__);
return 0;
}
apen = kzalloc(sizeof(*apen), GFP_KERNEL);
if (!apen) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for apen\n",
__func__);
retval = -ENOMEM;
goto exit;
}
apen->apen_data = kzalloc(sizeof(*(apen->apen_data)), GFP_KERNEL);
if (!apen->apen_data) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for apen_data\n",
__func__);
retval = -ENOMEM;
goto exit_free_apen;
}
apen->rmi4_data = rmi4_data;
retval = apen_scan_pdt();
if (retval < 0)
goto exit_free_apen_data;
apen->apen_dev = input_allocate_device();
if (apen->apen_dev == NULL) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to allocate active pen device\n",
__func__);
retval = -ENOMEM;
goto exit_free_apen_data;
}
apen->apen_dev->name = ACTIVE_PEN_DRIVER_NAME;
apen->apen_dev->phys = APEN_PHYS_NAME;
apen->apen_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
apen->apen_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
apen->apen_dev->dev.parent = rmi4_data->pdev->dev.parent;
input_set_drvdata(apen->apen_dev, rmi4_data);
set_bit(EV_KEY, apen->apen_dev->evbit);
set_bit(EV_ABS, apen->apen_dev->evbit);
set_bit(BTN_TOUCH, apen->apen_dev->keybit);
set_bit(BTN_TOOL_PEN, apen->apen_dev->keybit);
set_bit(BTN_TOOL_RUBBER, apen->apen_dev->keybit);
set_bit(BTN_STYLUS, apen->apen_dev->keybit);
#ifdef INPUT_PROP_DIRECT
set_bit(INPUT_PROP_DIRECT, apen->apen_dev->propbit);
#endif
apen_set_params();
retval = input_register_device(apen->apen_dev);
if (retval) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to register active pen device\n",
__func__);
goto exit_free_input_device;
}
return 0;
exit_free_input_device:
input_free_device(apen->apen_dev);
exit_free_apen_data:
kfree(apen->apen_data);
exit_free_apen:
kfree(apen);
apen = NULL;
exit:
return retval;
}
static void synaptics_rmi4_apen_remove(struct synaptics_rmi4_data *rmi4_data)
{
if (!apen)
goto exit;
input_unregister_device(apen->apen_dev);
kfree(apen->apen_data);
kfree(apen);
apen = NULL;
exit:
complete(&apen_remove_complete);
}
static void synaptics_rmi4_apen_reset(struct synaptics_rmi4_data *rmi4_data)
{
if (!apen) {
synaptics_rmi4_apen_init(rmi4_data);
return;
}
apen_lift();
apen_scan_pdt();
}
static void synaptics_rmi4_apen_reinit(struct synaptics_rmi4_data *rmi4_data)
{
if (!apen)
return;
apen_lift();
}
static void synaptics_rmi4_apen_e_suspend(struct synaptics_rmi4_data *rmi4_data)
{
if (!apen)
return;
apen_lift();
}
static void synaptics_rmi4_apen_suspend(struct synaptics_rmi4_data *rmi4_data)
{
if (!apen)
return;
apen_lift();
}
static struct synaptics_rmi4_exp_fn active_pen_module = {
.fn_type = RMI_ACTIVE_PEN,
.init = synaptics_rmi4_apen_init,
.remove = synaptics_rmi4_apen_remove,
.reset = synaptics_rmi4_apen_reset,
.reinit = synaptics_rmi4_apen_reinit,
.early_suspend = synaptics_rmi4_apen_e_suspend,
.suspend = synaptics_rmi4_apen_suspend,
.resume = NULL,
.late_resume = NULL,
.attn = synaptics_rmi4_apen_attn,
};
static int __init rmi4_active_pen_module_init(void)
{
synaptics_rmi4_new_function(&active_pen_module, true);
return 0;
}
static void __exit rmi4_active_pen_module_exit(void)
{
synaptics_rmi4_new_function(&active_pen_module, false);
wait_for_completion(&apen_remove_complete);
}
module_init(rmi4_active_pen_module_init);
module_exit(rmi4_active_pen_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX Active Pen Module");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,536 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#ifndef _SYNAPTICS_DSX_RMI4_H_
#define _SYNAPTICS_DSX_RMI4_H_
#define SYNAPTICS_DS4 (1 << 0)
#define SYNAPTICS_DS5 (1 << 1)
#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
#define SYNAPTICS_DSX_DRIVER_VERSION 0x2070
#include <linux/version.h>
#ifdef CONFIG_FB
#include <linux/notifier.h>
#include <linux/fb.h>
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <drm/drm_panel.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
#define KERNEL_ABOVE_2_6_38
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
#define KERNEL_ABOVE_3_6
#endif
#ifdef KERNEL_ABOVE_2_6_38
#define sstrtoul(...) kstrtoul(__VA_ARGS__)
#else
#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
#endif
#define PDT_PROPS (0X00EF)
#define PDT_START (0x00E9)
#define PDT_END (0x00D0)
#define PDT_ENTRY_SIZE (0x0006)
#define PAGES_TO_SERVICE (10)
#define PAGE_SELECT_LEN (2)
#define ADDRESS_LEN (2)
#define SYNAPTICS_RMI4_F01 (0x01)
#define SYNAPTICS_RMI4_F11 (0x11)
#define SYNAPTICS_RMI4_F12 (0x12)
#define SYNAPTICS_RMI4_F1A (0x1A)
#define SYNAPTICS_RMI4_F21 (0x21)
#define SYNAPTICS_RMI4_F34 (0x34)
#define SYNAPTICS_RMI4_F35 (0x35)
#define SYNAPTICS_RMI4_F38 (0x38)
#define SYNAPTICS_RMI4_F51 (0x51)
#define SYNAPTICS_RMI4_F54 (0x54)
#define SYNAPTICS_RMI4_F55 (0x55)
#define SYNAPTICS_RMI4_FDB (0xDB)
#define PRODUCT_INFO_SIZE 2
#define PRODUCT_ID_SIZE 10
#define BUILD_ID_SIZE 3
#define F12_FINGERS_TO_SUPPORT 10
#define F12_NO_OBJECT_STATUS 0x00
#define F12_FINGER_STATUS 0x01
#define F12_ACTIVE_STYLUS_STATUS 0x02
#define F12_PALM_STATUS 0x03
#define F12_HOVERING_FINGER_STATUS 0x05
#define F12_GLOVED_FINGER_STATUS 0x06
#define F12_NARROW_OBJECT_STATUS 0x07
#define F12_HAND_EDGE_STATUS 0x08
#define F12_COVER_STATUS 0x0A
#define F12_STYLUS_STATUS 0x0B
#define F12_ERASER_STATUS 0x0C
#define F12_SMALL_OBJECT_STATUS 0x0D
#define F12_GESTURE_DETECTION_LEN 5
#define MAX_NUMBER_OF_BUTTONS 4
#define MAX_INTR_REGISTERS 4
#define MASK_16BIT 0xFFFF
#define MASK_8BIT 0xFF
#define MASK_7BIT 0x7F
#define MASK_6BIT 0x3F
#define MASK_5BIT 0x1F
#define MASK_4BIT 0x0F
#define MASK_3BIT 0x07
#define MASK_2BIT 0x03
#define MASK_1BIT 0x01
#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
enum exp_fn {
RMI_DEV = 0,
RMI_FW_UPDATER,
RMI_TEST_REPORTING,
RMI_PROXIMITY,
RMI_ACTIVE_PEN,
RMI_GESTURE,
RMI_VIDEO,
RMI_DEBUG,
RMI_LAST,
};
extern struct drm_panel *active_panel;
/*
* struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
* @query_base_addr: base address for query registers
* @cmd_base_addr: base address for command registers
* @ctrl_base_addr: base address for control registers
* @data_base_addr: base address for data registers
* @intr_src_count: number of interrupt sources
* @fn_version: version of function
* @fn_number: function number
*/
struct synaptics_rmi4_fn_desc {
union {
struct {
unsigned char query_base_addr;
unsigned char cmd_base_addr;
unsigned char ctrl_base_addr;
unsigned char data_base_addr;
unsigned char intr_src_count:3;
unsigned char reserved_1:2;
unsigned char fn_version:2;
unsigned char reserved_2:1;
unsigned char fn_number;
} __packed;
unsigned char data[6];
};
};
/*
* synaptics_rmi4_fn_full_addr - full 16-bit base addresses
* @query_base: 16-bit base address for query registers
* @cmd_base: 16-bit base address for command registers
* @ctrl_base: 16-bit base address for control registers
* @data_base: 16-bit base address for data registers
*/
struct synaptics_rmi4_fn_full_addr {
unsigned short query_base;
unsigned short cmd_base;
unsigned short ctrl_base;
unsigned short data_base;
};
/*
* struct synaptics_rmi4_f11_extra_data - extra data of F$11
* @data38_offset: offset to F11_2D_DATA38 register
*/
struct synaptics_rmi4_f11_extra_data {
unsigned char data38_offset;
};
/*
* struct synaptics_rmi4_f12_extra_data - extra data of F$12
* @data1_offset: offset to F12_2D_DATA01 register
* @data4_offset: offset to F12_2D_DATA04 register
* @data15_offset: offset to F12_2D_DATA15 register
* @data15_size: size of F12_2D_DATA15 register
* @data15_data: buffer for reading F12_2D_DATA15 register
* @data29_offset: offset to F12_2D_DATA29 register
* @data29_size: size of F12_2D_DATA29 register
* @data29_data: buffer for reading F12_2D_DATA29 register
* @ctrl20_offset: offset to F12_2D_CTRL20 register
*/
struct synaptics_rmi4_f12_extra_data {
unsigned char data1_offset;
unsigned char data4_offset;
unsigned char data15_offset;
unsigned char data15_size;
unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
unsigned char data29_offset;
unsigned char data29_size;
unsigned char data29_data[F12_FINGERS_TO_SUPPORT * 2];
unsigned char ctrl20_offset;
};
/*
* struct synaptics_rmi4_fn - RMI function handler
* @fn_number: function number
* @num_of_data_sources: number of data sources
* @num_of_data_points: maximum number of fingers supported
* @intr_reg_num: index to associated interrupt register
* @intr_mask: interrupt mask
* @full_addr: full 16-bit base addresses of function registers
* @link: linked list for function handlers
* @data_size: size of private data
* @data: pointer to private data
* @extra: pointer to extra data
*/
struct synaptics_rmi4_fn {
unsigned char fn_number;
unsigned char num_of_data_sources;
unsigned char num_of_data_points;
unsigned char intr_reg_num;
unsigned char intr_mask;
struct synaptics_rmi4_fn_full_addr full_addr;
struct list_head link;
int data_size;
void *data;
void *extra;
};
/*
* struct synaptics_rmi4_input_settings - current input settings
* @num_of_fingers: maximum number of fingers for 2D touch
* @valid_button_count: number of valid 0D buttons
* @max_touch_width: maximum touch width
* @sensor_max_x: maximum x coordinate for 2D touch
* @sensor_max_y: maximum y coordinate for 2D touch
* @force_min: minimum force value
* @force_max: maximum force value
* @stylus_enable: flag to indicate reporting of stylus data
* @eraser_enable: flag to indicate reporting of eraser data
*/
struct synaptics_rmi4_input_settings {
unsigned char num_of_fingers;
unsigned char valid_button_count;
unsigned char max_touch_width;
int sensor_max_x;
int sensor_max_y;
int force_min;
int force_max;
bool stylus_enable;
bool eraser_enable;
};
/*
* struct synaptics_rmi4_device_info - device information
* @version_major: RMI protocol major version number
* @version_minor: RMI protocol minor version number
* @manufacturer_id: manufacturer ID
* @product_props: product properties
* @product_info: product information
* @product_id_string: product ID
* @build_id: firmware build ID
* @support_fn_list: linked list for function handlers
*/
struct synaptics_rmi4_device_info {
unsigned int version_major;
unsigned int version_minor;
unsigned char manufacturer_id;
unsigned char product_props;
unsigned char product_info[PRODUCT_INFO_SIZE];
unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
unsigned char build_id[BUILD_ID_SIZE];
struct list_head support_fn_list;
};
/*
* struct synaptics_rmi4_data - RMI4 device instance data
* @pdev: pointer to platform device
* @input_dev: pointer to associated input device
* @stylus_dev: pointer to associated stylus device
* @hw_if: pointer to hardware interface data
* @rmi4_mod_info: device information
* @board_prop_dir: /sys/board_properties directory for virtual key map file
* @pwr_reg: pointer to regulator for power control
* @bus_reg: pointer to regulator for bus pullup control
* @rmi4_reset_mutex: mutex for software reset
* @rmi4_report_mutex: mutex for input event reporting
* @rmi4_io_ctrl_mutex: mutex for communication interface I/O
* @rmi4_exp_init_mutex: mutex for expansion function module initialization
* @rmi4_irq_enable_mutex: mutex for enabling/disabling interrupt
* @rb_work: work for rebuilding input device
* @rb_workqueue: workqueue for rebuilding input device
* @fb_notifier: framebuffer notifier client
* @reset_work: work for issuing reset after display framebuffer ready
* @reset_workqueue: workqueue for issuing reset after display framebuffer ready
* @early_suspend: early suspend power management
* @current_page: current RMI page for register access
* @button_0d_enabled: switch for enabling 0d button support
* @num_of_tx: number of Tx channels for 2D touch
* @num_of_rx: number of Rx channels for 2D touch
* @num_of_fingers: maximum number of fingers for 2D touch
* @max_touch_width: maximum touch width
* @valid_button_count: number of valid 0D buttons
* @report_enable: input data to report for F$12
* @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register
* @gesture_detection: detected gesture type and properties
* @intr_mask: interrupt enable mask
* @button_txrx_mapping: Tx Rx mapping of 0D buttons
* @num_of_intr_regs: number of interrupt registers
* @f01_query_base_addr: query base address for f$01
* @f01_cmd_base_addr: command base address for f$01
* @f01_ctrl_base_addr: control base address for f$01
* @f01_data_base_addr: data base address for f$01
* @f51_query_base_addr: query base address for f$51
* @firmware_id: firmware build ID
* @irq: attention interrupt
* @sensor_max_x: maximum x coordinate for 2D touch
* @sensor_max_y: maximum y coordinate for 2D touch
* @force_min: minimum force value
* @force_max: maximum force value
* @set_wakeup_gesture: location of set wakeup gesture
* @flash_prog_mode: flag to indicate flash programming mode status
* @irq_enabled: flag to indicate attention interrupt enable status
* @fingers_on_2d: flag to indicate presence of fingers in 2D area
* @suspend: flag to indicate whether in suspend state
* @sensor_sleep: flag to indicate sleep state of sensor
* @stay_awake: flag to indicate whether to stay awake during suspend
* @fb_ready: flag to indicate whether display framebuffer in ready state
* @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11
* @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12
* @enable_wakeup_gesture: flag to indicate usage of wakeup gestures
* @wedge_sensor: flag to indicate use of wedge sensor
* @report_pressure: flag to indicate reporting of pressure data
* @stylus_enable: flag to indicate reporting of stylus data
* @eraser_enable: flag to indicate reporting of eraser data
* @external_afe_buttons: flag to indicate presence of external AFE buttons
* @notifier_cookie: touch notifier for panel events
* @reset_device: pointer to device reset function
* @irq_enable: pointer to interrupt enable function
* @sleep_enable: pointer to sleep enable function
* @report_touch: pointer to touch reporting function
*/
struct synaptics_rmi4_data {
bool initialized;
struct platform_device *pdev;
struct input_dev *input_dev;
struct input_dev *stylus_dev;
const struct synaptics_dsx_hw_interface *hw_if;
struct synaptics_rmi4_device_info rmi4_mod_info;
struct synaptics_rmi4_input_settings input_settings;
struct kobject *board_prop_dir;
struct regulator *pwr_reg;
struct regulator *bus_reg;
struct mutex rmi4_reset_mutex;
struct mutex rmi4_report_mutex;
struct mutex rmi4_io_ctrl_mutex;
struct mutex rmi4_exp_init_mutex;
struct mutex rmi4_irq_enable_mutex;
struct delayed_work rb_work;
struct workqueue_struct *rb_workqueue;
struct work_struct rmi4_probe_work;
struct workqueue_struct *rmi4_probe_wq;
struct completion drm_init_done;
struct pinctrl *ts_pinctrl;
struct pinctrl_state *pinctrl_state_active;
struct pinctrl_state *pinctrl_state_suspend;
struct pinctrl_state *pinctrl_state_release;
struct notifier_block fb_notifier;
struct work_struct reset_work;
struct workqueue_struct *reset_workqueue;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
unsigned char current_page;
unsigned char button_0d_enabled;
unsigned char num_of_tx;
unsigned char num_of_rx;
unsigned char num_of_fingers;
unsigned char max_touch_width;
unsigned char valid_button_count;
unsigned char report_enable;
unsigned char no_sleep_setting;
unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
unsigned char intr_mask[MAX_INTR_REGISTERS];
unsigned char *button_txrx_mapping;
unsigned short num_of_intr_regs;
unsigned short f01_query_base_addr;
unsigned short f01_cmd_base_addr;
unsigned short f01_ctrl_base_addr;
unsigned short f01_data_base_addr;
#ifdef F51_DISCRETE_FORCE
unsigned short f51_query_base_addr;
#endif
unsigned int firmware_id;
int irq;
int sensor_max_x;
int sensor_max_y;
int force_min;
int force_max;
int set_wakeup_gesture;
int avdd_status;
int vdd_status;
bool flash_prog_mode;
bool irq_enabled;
bool fingers_on_2d;
bool suspend;
bool sensor_sleep;
bool stay_awake;
bool fb_ready;
bool f11_wakeup_gesture;
bool f12_wakeup_gesture;
bool enable_wakeup_gesture;
bool wedge_sensor;
bool report_pressure;
bool stylus_enable;
bool eraser_enable;
bool external_afe_buttons;
void *notifier_cookie;
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data,
bool rebuild);
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable,
bool attn_only);
int (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
bool enable);
void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
struct synaptics_rmi4_fn *fhandler);
};
struct synaptics_dsx_bus_access {
unsigned char type;
int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
unsigned char *data, unsigned int length);
int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
unsigned char *data, unsigned int length);
};
struct synaptics_dsx_hw_interface {
struct synaptics_dsx_board_data *board_data;
const struct synaptics_dsx_bus_access *bus_access;
int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data);
int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data);
};
struct synaptics_rmi4_exp_fn {
enum exp_fn fn_type;
int (*init)(struct synaptics_rmi4_data *rmi4_data);
void (*remove)(struct synaptics_rmi4_data *rmi4_data);
void (*reset)(struct synaptics_rmi4_data *rmi4_data);
void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
void (*resume)(struct synaptics_rmi4_data *rmi4_data);
void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
void (*attn)(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask);
};
int synaptics_rmi4_bus_init(void);
void synaptics_rmi4_bus_exit(void);
void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
bool insert);
int synaptics_fw_updater(const unsigned char *fw_data);
static inline int synaptics_rmi4_reg_read(
struct synaptics_rmi4_data *rmi4_data,
unsigned short addr,
unsigned char *data,
unsigned int len)
{
return rmi4_data->hw_if->bus_access->read(rmi4_data, addr, data, len);
}
static inline int synaptics_rmi4_reg_write(
struct synaptics_rmi4_data *rmi4_data,
unsigned short addr,
unsigned char *data,
unsigned int len)
{
return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
}
static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
struct device_attribute *attr, char *buf)
{
dev_warn(dev, "%s Attempted to read from write-only attribute %s\n",
__func__, attr->attr.name);
return -EPERM;
}
static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
dev_warn(dev, "%s Attempted to write to read-only attribute %s\n",
__func__, attr->attr.name);
return -EPERM;
}
static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
const unsigned char *src, unsigned int src_size,
unsigned int count)
{
if (dest == NULL || src == NULL)
return -EINVAL;
if (count > dest_size || count > src_size)
return -EINVAL;
memcpy((void *)dest, (const void *)src, count);
return 0;
}
static inline void batohs(unsigned short *dest, unsigned char *src)
{
*dest = src[1] * 0x100 + src[0];
}
static inline void hstoba(unsigned char *dest, unsigned short src)
{
dest[0] = src % 0x100;
dest[1] = src / 0x100;
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,672 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/types.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#include "linux/moduleparam.h"
#define SYN_I2C_RETRY_TIMES 10
#define rd_msgs 1
#ifdef CONFIG_DRM
#include <drm/drm_panel.h>
struct drm_panel *active_panel;
#endif
static unsigned char *wr_buf;
static struct synaptics_dsx_hw_interface hw_if;
static struct platform_device *synaptics_dsx_i2c_device;
#ifdef CONFIG_OF
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
{
int retval;
u32 value;
const char *name;
struct property *prop;
struct device_node *np = dev->of_node;
bdata->irq_gpio = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
retval = of_property_read_u32(np, "synaptics,irq-on-state",
&value);
if (retval < 0)
bdata->irq_on_state = 0;
else
bdata->irq_on_state = value;
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
else
bdata->pwr_reg_name = name;
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
if (retval < 0)
bdata->bus_reg_name = NULL;
else
bdata->bus_reg_name = name;
prop = of_find_property(np, "synaptics,power-gpio", NULL);
if (prop && prop->length) {
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,power-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
__func__);
return retval;
}
bdata->power_on_state = value;
} else {
bdata->power_gpio = -1;
}
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
__func__);
return retval;
}
bdata->power_delay_ms = value;
} else {
bdata->power_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
if (prop && prop->length) {
bdata->reset_gpio = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
__func__);
return retval;
}
bdata->reset_on_state = value;
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
__func__);
return retval;
}
bdata->reset_active_ms = value;
} else {
bdata->reset_gpio = -1;
}
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
__func__);
return retval;
}
bdata->reset_delay_ms = value;
} else {
bdata->reset_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
__func__);
return retval;
}
bdata->max_y_for_2d = value;
} else {
bdata->max_y_for_2d = -1;
}
bdata->swap_axes = of_property_read_bool(np, "synaptics,swap-axes");
bdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
bdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
__func__);
return retval;
}
bdata->ub_i2c_addr = (unsigned short)value;
} else {
bdata->ub_i2c_addr = -1;
}
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
if (prop && prop->length) {
bdata->cap_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->cap_button_map->map)
return -ENOMEM;
bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
retval = of_property_read_u32_array(np,
"synaptics,cap-button-codes",
bdata->cap_button_map->map,
bdata->cap_button_map->nbuttons);
if (retval < 0) {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
} else {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
if (prop && prop->length) {
bdata->vir_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->vir_button_map->map)
return -ENOMEM;
bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
bdata->vir_button_map->nbuttons /= 5;
retval = of_property_read_u32_array(np,
"synaptics,vir-button-codes",
bdata->vir_button_map->map,
bdata->vir_button_map->nbuttons * 5);
if (retval < 0) {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
} else {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
return 0;
}
#endif
static int synaptics_rmi4_i2c_alloc_buf(struct synaptics_rmi4_data *rmi4_data,
unsigned int count)
{
static unsigned int buf_size;
if (count > buf_size) {
if (buf_size)
kfree(wr_buf);
wr_buf = kzalloc(count, GFP_KERNEL);
if (!wr_buf) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for buffer\n",
__func__);
buf_size = 0;
return -ENOMEM;
}
buf_size = count;
}
return 0;
}
static void synaptics_rmi4_i2c_check_addr(struct synaptics_rmi4_data *rmi4_data,
struct i2c_client *i2c)
{
if (hw_if.board_data->ub_i2c_addr == -1)
return;
if (hw_if.board_data->i2c_addr == i2c->addr)
hw_if.board_data->i2c_addr = hw_if.board_data->ub_i2c_addr;
else
hw_if.board_data->i2c_addr = i2c->addr;
}
static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr)
{
int retval = 0;
unsigned char retry;
unsigned char buf[PAGE_SELECT_LEN];
unsigned char page;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_msg msg[2];
msg[0].addr = hw_if.board_data->i2c_addr;
msg[0].flags = 0;
msg[0].len = PAGE_SELECT_LEN;
msg[0].buf = buf;
page = ((addr >> 8) & MASK_8BIT);
buf[0] = MASK_8BIT;
buf[1] = page;
if (page != rmi4_data->current_page) {
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(i2c->adapter, &msg[0], 1) == 1) {
rmi4_data->current_page = page;
retval = PAGE_SELECT_LEN;
break;
}
dev_err(rmi4_data->pdev->dev.parent,
"%s: I2C retry %d\n",
__func__, retry + 1);
msleep(20);
if (retry == SYN_I2C_RETRY_TIMES / 2) {
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
msg[0].addr = hw_if.board_data->i2c_addr;
}
}
} else {
retval = PAGE_SELECT_LEN;
}
return retval;
}
static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval = 0;
unsigned char retry;
unsigned char buf;
unsigned char index = 0;
unsigned char xfer_msgs;
unsigned char remaining_msgs;
unsigned short i2c_addr;
unsigned short data_offset = 0;
unsigned int remaining_length = length;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_adapter *adap = i2c->adapter;
struct i2c_msg msg[rd_msgs + 1];
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
if (retval != PAGE_SELECT_LEN) {
retval = -EIO;
goto exit;
}
msg[0].addr = hw_if.board_data->i2c_addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &buf;
msg[rd_msgs].addr = hw_if.board_data->i2c_addr;
msg[rd_msgs].flags = I2C_M_RD;
msg[rd_msgs].len = (unsigned short)remaining_length;
msg[rd_msgs].buf = &data[data_offset];
buf = addr & MASK_8BIT;
remaining_msgs = rd_msgs + 1;
while (remaining_msgs) {
xfer_msgs = remaining_msgs;
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
retval = i2c_transfer(adap, &msg[index], xfer_msgs);
if (retval == xfer_msgs)
break;
dev_err(rmi4_data->pdev->dev.parent,
"%s: I2C retry %d\n",
__func__, retry + 1);
msleep(20);
if (retry == SYN_I2C_RETRY_TIMES / 2) {
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
i2c_addr = hw_if.board_data->i2c_addr;
msg[0].addr = i2c_addr;
msg[rd_msgs].addr = i2c_addr;
}
}
if (retry == SYN_I2C_RETRY_TIMES) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: I2C read over retry limit\n",
__func__);
retval = -EIO;
goto exit;
}
remaining_msgs -= xfer_msgs;
index += xfer_msgs;
}
retval = length;
exit:
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned char retry;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_msg msg[2];
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
if (retval < 0)
goto exit;
retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
if (retval != PAGE_SELECT_LEN) {
retval = -EIO;
goto exit;
}
msg[0].addr = hw_if.board_data->i2c_addr;
msg[0].flags = 0;
msg[0].len = (unsigned short)(length + 1);
msg[0].buf = wr_buf;
wr_buf[0] = addr & MASK_8BIT;
retval = secure_memcpy(&wr_buf[1], length, &data[0], length, length);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
goto exit;
}
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(i2c->adapter, &msg[0], 1) == 1) {
retval = length;
break;
}
dev_err(rmi4_data->pdev->dev.parent,
"%s: I2C retry %d\n",
__func__, retry + 1);
msleep(20);
if (retry == SYN_I2C_RETRY_TIMES / 2) {
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
msg[0].addr = hw_if.board_data->i2c_addr;
}
}
if (retry == SYN_I2C_RETRY_TIMES) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: I2C write over retry limit\n",
__func__);
retval = -EIO;
}
exit:
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
#ifdef CONFIG_DRM
static int check_dt(struct device_node *np)
{
int i;
int count;
struct device_node *node;
struct drm_panel *panel;
count = of_count_phandle_with_args(np, "panel", NULL);
if (count <= 0)
return 0;
for (i = 0; i < count; i++) {
node = of_parse_phandle(np, "panel", i);
panel = of_drm_find_panel(node);
of_node_put(node);
if (!IS_ERR(panel)) {
active_panel = panel;
return 0;
}
}
return PTR_ERR(panel);
}
#endif
static int check_default_tp(struct device_node *dt, const char *prop)
{
const char *active_tp;
const char *compatible;
char *start;
int ret;
ret = of_property_read_string(dt->parent, prop, &active_tp);
if (ret) {
pr_err(" %s:fail to read %s %d\n", __func__, prop, ret);
return -ENODEV;
}
ret = of_property_read_string(dt, "compatible", &compatible);
if (ret < 0) {
pr_err(" %s:fail to read %s %d\n", __func__, "compatible", ret);
return -ENODEV;
}
start = strnstr(active_tp, compatible, strlen(active_tp));
if (start == NULL) {
pr_err(" %s:no match compatible, %s, %s\n",
__func__, compatible, active_tp);
ret = -ENODEV;
}
return ret;
}
static struct synaptics_dsx_bus_access bus_access = {
.type = BUS_I2C,
.read = synaptics_rmi4_i2c_read,
.write = synaptics_rmi4_i2c_write,
};
static void synaptics_rmi4_i2c_dev_release(struct device *dev)
{
kfree(synaptics_dsx_i2c_device);
}
static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int retval;
struct device_node *dp = client->dev.of_node;
#ifdef CONFIG_DRM
retval = check_dt(dp);
if (retval == -EPROBE_DEFER)
return retval;
if (retval) {
if (!check_default_tp(dp, "qcom,i2c-touch-active"))
retval = -EPROBE_DEFER;
else
retval = -ENODEV;
return retval;
}
#endif
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
"%s: SMBus byte data commands not supported by host\n",
__func__);
return -EIO;
}
synaptics_dsx_i2c_device = kzalloc(
sizeof(struct platform_device),
GFP_KERNEL);
if (!synaptics_dsx_i2c_device) {
dev_err(&client->dev,
"%s: Failed to allocate memory for synaptics_dsx_i2c_device\n",
__func__);
return -ENOMEM;
}
#ifdef CONFIG_OF
if (client->dev.of_node) {
hw_if.board_data = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_board_data),
GFP_KERNEL);
if (!hw_if.board_data) {
dev_err(&client->dev,
"%s: Failed to allocate memory for board data\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->cap_button_map) {
dev_err(&client->dev,
"%s: Failed to allocate memory for 0D button map\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->vir_button_map) {
dev_err(&client->dev,
"%s: Failed to allocate memory for virtual button map\n",
__func__);
return -ENOMEM;
}
parse_dt(&client->dev, hw_if.board_data);
}
#else
hw_if.board_data = client->dev.platform_data;
#endif
hw_if.bus_access = &bus_access;
hw_if.board_data->i2c_addr = client->addr;
synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
synaptics_dsx_i2c_device->id = 0;
synaptics_dsx_i2c_device->num_resources = 0;
synaptics_dsx_i2c_device->dev.parent = &client->dev;
synaptics_dsx_i2c_device->dev.platform_data = &hw_if;
synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release;
retval = platform_device_register(synaptics_dsx_i2c_device);
if (retval) {
dev_err(&client->dev,
"%s: Failed to register platform device\n",
__func__);
return -ENODEV;
}
return 0;
}
static int synaptics_rmi4_i2c_remove(struct i2c_client *client)
{
platform_device_unregister(synaptics_dsx_i2c_device);
return 0;
}
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
{I2C_DRIVER_NAME, 0},
{},
};
MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
#ifdef CONFIG_OF
static const struct of_device_id synaptics_rmi4_of_match_table[] = {
{
.compatible = "synaptics,dsx-i2c",
},
{},
};
MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
#else
#define synaptics_rmi4_of_match_table NULL
#endif
static struct i2c_driver synaptics_rmi4_i2c_driver = {
.driver = {
.name = I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = synaptics_rmi4_of_match_table,
},
.probe = synaptics_rmi4_i2c_probe,
.remove = synaptics_rmi4_i2c_remove,
.id_table = synaptics_rmi4_id_table,
};
int synaptics_rmi4_bus_init(void)
{
return i2c_add_driver(&synaptics_rmi4_i2c_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_init);
void synaptics_rmi4_bus_exit(void)
{
kfree(wr_buf);
i2c_del_driver(&synaptics_rmi4_i2c_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,673 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#define PROX_PHYS_NAME "synaptics_dsx/proximity"
#define HOVER_Z_MAX (255)
#define HOVERING_FINGER_EN (1 << 4)
static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
static struct device_attribute attrs[] = {
__ATTR(hover_finger_en, 0664,
synaptics_rmi4_hover_finger_en_show,
synaptics_rmi4_hover_finger_en_store),
};
struct synaptics_rmi4_f12_query_5 {
union {
struct {
unsigned char size_of_query6;
struct {
unsigned char ctrl0_is_present:1;
unsigned char ctrl1_is_present:1;
unsigned char ctrl2_is_present:1;
unsigned char ctrl3_is_present:1;
unsigned char ctrl4_is_present:1;
unsigned char ctrl5_is_present:1;
unsigned char ctrl6_is_present:1;
unsigned char ctrl7_is_present:1;
} __packed;
struct {
unsigned char ctrl8_is_present:1;
unsigned char ctrl9_is_present:1;
unsigned char ctrl10_is_present:1;
unsigned char ctrl11_is_present:1;
unsigned char ctrl12_is_present:1;
unsigned char ctrl13_is_present:1;
unsigned char ctrl14_is_present:1;
unsigned char ctrl15_is_present:1;
} __packed;
struct {
unsigned char ctrl16_is_present:1;
unsigned char ctrl17_is_present:1;
unsigned char ctrl18_is_present:1;
unsigned char ctrl19_is_present:1;
unsigned char ctrl20_is_present:1;
unsigned char ctrl21_is_present:1;
unsigned char ctrl22_is_present:1;
unsigned char ctrl23_is_present:1;
} __packed;
};
unsigned char data[4];
};
};
struct synaptics_rmi4_f12_query_8 {
union {
struct {
unsigned char size_of_query9;
struct {
unsigned char data0_is_present:1;
unsigned char data1_is_present:1;
unsigned char data2_is_present:1;
unsigned char data3_is_present:1;
unsigned char data4_is_present:1;
unsigned char data5_is_present:1;
unsigned char data6_is_present:1;
unsigned char data7_is_present:1;
} __packed;
};
unsigned char data[2];
};
};
struct prox_finger_data {
union {
struct {
unsigned char object_type_and_status;
unsigned char x_lsb;
unsigned char x_msb;
unsigned char y_lsb;
unsigned char y_msb;
unsigned char z;
} __packed;
unsigned char proximity_data[6];
};
};
struct synaptics_rmi4_prox_handle {
bool hover_finger_present;
bool hover_finger_en;
unsigned char intr_mask;
unsigned short query_base_addr;
unsigned short control_base_addr;
unsigned short data_base_addr;
unsigned short command_base_addr;
unsigned short hover_finger_en_addr;
unsigned short hover_finger_data_addr;
struct input_dev *prox_dev;
struct prox_finger_data *finger_data;
struct synaptics_rmi4_data *rmi4_data;
};
static struct synaptics_rmi4_prox_handle *prox;
DECLARE_COMPLETION(prox_remove_complete);
static void prox_hover_finger_lift(void)
{
input_report_key(prox->prox_dev, BTN_TOUCH, 0);
input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0);
input_sync(prox->prox_dev);
prox->hover_finger_present = false;
}
static void prox_hover_finger_report(void)
{
int retval;
int x;
int y;
int z;
struct prox_finger_data *data;
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
data = prox->finger_data;
retval = synaptics_rmi4_reg_read(rmi4_data,
prox->hover_finger_data_addr,
data->proximity_data,
sizeof(data->proximity_data));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read hovering finger data\n",
__func__);
return;
}
if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) {
if (prox->hover_finger_present)
prox_hover_finger_lift();
return;
}
x = (data->x_msb << 8) | (data->x_lsb);
y = (data->y_msb << 8) | (data->y_lsb);
z = HOVER_Z_MAX - data->z;
input_report_key(prox->prox_dev, BTN_TOUCH, 0);
input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1);
input_report_abs(prox->prox_dev, ABS_X, x);
input_report_abs(prox->prox_dev, ABS_Y, y);
input_report_abs(prox->prox_dev, ABS_DISTANCE, z);
input_sync(prox->prox_dev);
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: x = %d y = %d z = %d\n",
__func__, x, y, z);
prox->hover_finger_present = true;
}
static int prox_set_hover_finger_en(void)
{
int retval;
unsigned char object_report_enable;
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
retval = synaptics_rmi4_reg_read(rmi4_data,
prox->hover_finger_en_addr,
&object_report_enable,
sizeof(object_report_enable));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read from object report enable register\n",
__func__);
return retval;
}
if (prox->hover_finger_en)
object_report_enable |= HOVERING_FINGER_EN;
else
object_report_enable &= ~HOVERING_FINGER_EN;
retval = synaptics_rmi4_reg_write(rmi4_data,
prox->hover_finger_en_addr,
&object_report_enable,
sizeof(object_report_enable));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to write to object report enable register\n",
__func__);
return retval;
}
return 0;
}
static void prox_set_params(void)
{
input_set_abs_params(prox->prox_dev, ABS_X, 0,
prox->rmi4_data->sensor_max_x, 0, 0);
input_set_abs_params(prox->prox_dev, ABS_Y, 0,
prox->rmi4_data->sensor_max_y, 0, 0);
input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0,
HOVER_Z_MAX, 0, 0);
}
static int prox_reg_init(void)
{
int retval;
unsigned char ctrl_23_offset;
unsigned char data_1_offset;
struct synaptics_rmi4_f12_query_5 query_5;
struct synaptics_rmi4_f12_query_8 query_8;
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
retval = synaptics_rmi4_reg_read(rmi4_data,
prox->query_base_addr + 5,
query_5.data,
sizeof(query_5.data));
if (retval < 0)
return retval;
ctrl_23_offset = query_5.ctrl0_is_present +
query_5.ctrl1_is_present +
query_5.ctrl2_is_present +
query_5.ctrl3_is_present +
query_5.ctrl4_is_present +
query_5.ctrl5_is_present +
query_5.ctrl6_is_present +
query_5.ctrl7_is_present +
query_5.ctrl8_is_present +
query_5.ctrl9_is_present +
query_5.ctrl10_is_present +
query_5.ctrl11_is_present +
query_5.ctrl12_is_present +
query_5.ctrl13_is_present +
query_5.ctrl14_is_present +
query_5.ctrl15_is_present +
query_5.ctrl16_is_present +
query_5.ctrl17_is_present +
query_5.ctrl18_is_present +
query_5.ctrl19_is_present +
query_5.ctrl20_is_present +
query_5.ctrl21_is_present +
query_5.ctrl22_is_present;
prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset;
retval = synaptics_rmi4_reg_read(rmi4_data,
prox->query_base_addr + 8,
query_8.data,
sizeof(query_8.data));
if (retval < 0)
return retval;
data_1_offset = query_8.data0_is_present;
prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset;
return retval;
}
static int prox_scan_pdt(void)
{
int retval;
unsigned char ii;
unsigned char page;
unsigned char intr_count = 0;
unsigned char intr_off;
unsigned char intr_src;
unsigned short addr;
struct synaptics_rmi4_fn_desc fd;
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
for (page = 0; page < PAGES_TO_SERVICE; page++) {
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
addr |= (page << 8);
retval = synaptics_rmi4_reg_read(rmi4_data,
addr,
(unsigned char *)&fd,
sizeof(fd));
if (retval < 0)
return retval;
addr &= ~(MASK_8BIT << 8);
if (fd.fn_number) {
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Found F%02x\n",
__func__, fd.fn_number);
switch (fd.fn_number) {
case SYNAPTICS_RMI4_F12:
goto f12_found;
break;
}
} else {
break;
}
intr_count += fd.intr_src_count;
}
}
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to find F12\n",
__func__);
return -EINVAL;
f12_found:
prox->query_base_addr = fd.query_base_addr | (page << 8);
prox->control_base_addr = fd.ctrl_base_addr | (page << 8);
prox->data_base_addr = fd.data_base_addr | (page << 8);
prox->command_base_addr = fd.cmd_base_addr | (page << 8);
retval = prox_reg_init();
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to initialize proximity registers\n",
__func__);
return retval;
}
prox->intr_mask = 0;
intr_src = fd.intr_src_count;
intr_off = intr_count % 8;
for (ii = intr_off;
ii < (intr_src + intr_off);
ii++) {
prox->intr_mask |= 1 << ii;
}
rmi4_data->intr_mask[0] |= prox->intr_mask;
addr = rmi4_data->f01_ctrl_base_addr + 1;
retval = synaptics_rmi4_reg_write(rmi4_data,
addr,
&(rmi4_data->intr_mask[0]),
sizeof(rmi4_data->intr_mask[0]));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to set interrupt enable bit\n",
__func__);
return retval;
}
return 0;
}
static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
if (!prox)
return -ENODEV;
return snprintf(buf, PAGE_SIZE, "%u\n",
prox->hover_finger_en);
}
static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int retval;
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
if (!prox)
return -ENODEV;
if (kstrtouint(buf, 16, &input) != 1)
return -EINVAL;
if (input == 1)
prox->hover_finger_en = true;
else if (input == 0)
prox->hover_finger_en = false;
else
return -EINVAL;
retval = prox_set_hover_finger_en();
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to change hovering finger enable setting\n",
__func__);
return retval;
}
return count;
}
int synaptics_rmi4_prox_hover_finger_en(bool enable)
{
int retval;
if (!prox)
return -ENODEV;
prox->hover_finger_en = enable;
retval = prox_set_hover_finger_en();
if (retval < 0)
return retval;
return 0;
}
EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en);
static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask)
{
if (!prox)
return;
if (prox->intr_mask & intr_mask)
prox_hover_finger_report();
}
static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned char attr_count;
if (prox) {
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Handle already exists\n",
__func__);
return 0;
}
prox = kzalloc(sizeof(*prox), GFP_KERNEL);
if (!prox) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for prox\n",
__func__);
retval = -ENOMEM;
goto exit;
}
prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL);
if (!prox->finger_data) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for finger_data\n",
__func__);
retval = -ENOMEM;
goto exit_free_prox;
}
prox->rmi4_data = rmi4_data;
retval = prox_scan_pdt();
if (retval < 0)
goto exit_free_finger_data;
prox->hover_finger_en = true;
retval = prox_set_hover_finger_en();
if (retval < 0)
return retval;
prox->prox_dev = input_allocate_device();
if (prox->prox_dev == NULL) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to allocate proximity device\n",
__func__);
retval = -ENOMEM;
goto exit_free_finger_data;
}
prox->prox_dev->name = PROXIMITY_DRIVER_NAME;
prox->prox_dev->phys = PROX_PHYS_NAME;
prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent;
input_set_drvdata(prox->prox_dev, rmi4_data);
set_bit(EV_KEY, prox->prox_dev->evbit);
set_bit(EV_ABS, prox->prox_dev->evbit);
set_bit(BTN_TOUCH, prox->prox_dev->keybit);
set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit);
#ifdef INPUT_PROP_DIRECT
set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit);
#endif
prox_set_params();
retval = input_register_device(prox->prox_dev);
if (retval) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to register proximity device\n",
__func__);
goto exit_free_input_device;
}
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to create sysfs attributes\n",
__func__);
goto exit_free_sysfs;
}
}
return 0;
exit_free_sysfs:
for (attr_count--; attr_count >= 0; attr_count--) {
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
input_unregister_device(prox->prox_dev);
prox->prox_dev = NULL;
exit_free_input_device:
if (prox->prox_dev)
input_free_device(prox->prox_dev);
exit_free_finger_data:
kfree(prox->finger_data);
exit_free_prox:
kfree(prox);
prox = NULL;
exit:
return retval;
}
static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data)
{
unsigned char attr_count;
if (!prox)
goto exit;
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
&attrs[attr_count].attr);
}
input_unregister_device(prox->prox_dev);
kfree(prox->finger_data);
kfree(prox);
prox = NULL;
exit:
complete(&prox_remove_complete);
}
static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data)
{
if (!prox) {
synaptics_rmi4_prox_init(rmi4_data);
return;
}
prox_hover_finger_lift();
prox_scan_pdt();
prox_set_hover_finger_en();
}
static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data)
{
if (!prox)
return;
prox_hover_finger_lift();
prox_set_hover_finger_en();
}
static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data)
{
if (!prox)
return;
prox_hover_finger_lift();
}
static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data)
{
if (!prox)
return;
prox_hover_finger_lift();
}
static struct synaptics_rmi4_exp_fn proximity_module = {
.fn_type = RMI_PROXIMITY,
.init = synaptics_rmi4_prox_init,
.remove = synaptics_rmi4_prox_remove,
.reset = synaptics_rmi4_prox_reset,
.reinit = synaptics_rmi4_prox_reinit,
.early_suspend = synaptics_rmi4_prox_e_suspend,
.suspend = synaptics_rmi4_prox_suspend,
.resume = NULL,
.late_resume = NULL,
.attn = synaptics_rmi4_prox_attn,
};
static int __init rmi4_proximity_module_init(void)
{
synaptics_rmi4_new_function(&proximity_module, true);
return 0;
}
static void __exit rmi4_proximity_module_exit(void)
{
synaptics_rmi4_new_function(&proximity_module, false);
wait_for_completion(&prox_remove_complete);
}
module_init(rmi4_proximity_module_init);
module_exit(rmi4_proximity_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX Proximity Module");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,989 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#define SYN_I2C_RETRY_TIMES 10
#define REPORT_ID_GET_BLOB 0x07
#define REPORT_ID_WRITE 0x09
#define REPORT_ID_READ_ADDRESS 0x0a
#define REPORT_ID_READ_DATA 0x0b
#define REPORT_ID_SET_RMI_MODE 0x0f
#define PREFIX_USAGE_PAGE_1BYTE 0x05
#define PREFIX_USAGE_PAGE_2BYTES 0x06
#define PREFIX_USAGE 0x09
#define PREFIX_REPORT_ID 0x85
#define PREFIX_REPORT_COUNT_1BYTE 0x95
#define PREFIX_REPORT_COUNT_2BYTES 0x96
#define USAGE_GET_BLOB 0xc5
#define USAGE_WRITE 0x02
#define USAGE_READ_ADDRESS 0x03
#define USAGE_READ_DATA 0x04
#define USAGE_SET_MODE 0x06
#define FEATURE_REPORT_TYPE 0x03
#define VENDOR_DEFINED_PAGE 0xff00
#define BLOB_REPORT_SIZE 256
#define RESET_COMMAND 0x01
#define GET_REPORT_COMMAND 0x02
#define SET_REPORT_COMMAND 0x03
#define SET_POWER_COMMAND 0x08
#define FINGER_MODE 0x00
#define RMI_MODE 0x02
struct hid_report_info {
unsigned char get_blob_id;
unsigned char write_id;
unsigned char read_addr_id;
unsigned char read_data_id;
unsigned char set_mode_id;
unsigned int blob_size;
};
static struct hid_report_info hid_report;
struct hid_device_descriptor {
unsigned short device_descriptor_length;
unsigned short format_version;
unsigned short report_descriptor_length;
unsigned short report_descriptor_index;
unsigned short input_register_index;
unsigned short input_report_max_length;
unsigned short output_register_index;
unsigned short output_report_max_length;
unsigned short command_register_index;
unsigned short data_register_index;
unsigned short vendor_id;
unsigned short product_id;
unsigned short version_id;
unsigned int reserved;
};
static struct hid_device_descriptor hid_dd;
struct i2c_rw_buffer {
unsigned char *read;
unsigned char *write;
unsigned int read_size;
unsigned int write_size;
};
static struct i2c_rw_buffer buffer;
#ifdef CONFIG_OF
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
{
int retval;
u32 value;
const char *name;
struct property *prop;
struct device_node *np = dev->of_node;
bdata->irq_gpio = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
retval = of_property_read_u32(np, "synaptics,irq-on-state",
&value);
if (retval < 0)
bdata->irq_on_state = 0;
else
bdata->irq_on_state = value;
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
else
bdata->pwr_reg_name = name;
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
if (retval < 0)
bdata->bus_reg_name = NULL;
else
bdata->bus_reg_name = name;
prop = of_find_property(np, "synaptics,power-gpio", NULL);
if (prop && prop->length) {
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,power-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
__func__);
return retval;
}
bdata->power_on_state = value;
} else {
bdata->power_gpio = -1;
}
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
__func__);
return retval;
}
bdata->power_delay_ms = value;
} else {
bdata->power_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
if (prop && prop->length) {
bdata->reset_gpio = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
__func__);
return retval;
}
bdata->reset_on_state = value;
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
__func__);
return retval;
}
bdata->reset_active_ms = value;
} else {
bdata->reset_gpio = -1;
}
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
__func__);
return retval;
}
bdata->reset_delay_ms = value;
} else {
bdata->reset_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,dev-dscrptr-addr", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,dev-dscrptr-addr",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,dev-dscrptr-addr property\n",
__func__);
return retval;
}
bdata->device_descriptor_addr = (unsigned short)value;
} else {
bdata->device_descriptor_addr = 0;
}
prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
__func__);
return retval;
}
bdata->max_y_for_2d = value;
} else {
bdata->max_y_for_2d = -1;
}
prop = of_find_property(np, "synaptics,swap-axes", NULL);
bdata->swap_axes = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,x-flip", NULL);
bdata->x_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,y-flip", NULL);
bdata->y_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
__func__);
return retval;
}
bdata->ub_i2c_addr = (unsigned short)value;
} else {
bdata->ub_i2c_addr = -1;
}
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
if (prop && prop->length) {
bdata->cap_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->cap_button_map->map)
return -ENOMEM;
bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
retval = of_property_read_u32_array(np,
"synaptics,cap-button-codes",
bdata->cap_button_map->map,
bdata->cap_button_map->nbuttons);
if (retval < 0) {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
} else {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
if (prop && prop->length) {
bdata->vir_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->vir_button_map->map)
return -ENOMEM;
bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
bdata->vir_button_map->nbuttons /= 5;
retval = of_property_read_u32_array(np,
"synaptics,vir-button-codes",
bdata->vir_button_map->map,
bdata->vir_button_map->nbuttons * 5);
if (retval < 0) {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
} else {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
return 0;
}
#endif
static int do_i2c_transfer(struct i2c_client *client, struct i2c_msg *msg)
{
unsigned char retry;
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
if (i2c_transfer(client->adapter, msg, 1) == 1)
break;
dev_err(&client->dev,
"%s: I2C retry %d\n",
__func__, retry + 1);
msleep(20);
}
if (retry == SYN_I2C_RETRY_TIMES) {
dev_err(&client->dev,
"%s: I2C transfer over retry limit\n",
__func__);
return -EIO;
}
return 0;
}
static int check_buffer(unsigned char **buffer, unsigned int *buffer_size,
unsigned int length)
{
if (*buffer_size < length) {
if (*buffer_size)
kfree(*buffer);
*buffer = kzalloc(length, GFP_KERNEL);
if (!(*buffer))
return -ENOMEM;
*buffer_size = length;
}
return 0;
}
static int generic_read(struct i2c_client *client, unsigned short length)
{
int retval;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = length,
}
};
check_buffer(&buffer.read, &buffer.read_size, length);
msg[0].buf = buffer.read;
retval = do_i2c_transfer(client, msg);
return retval;
}
static int generic_write(struct i2c_client *client, unsigned short length)
{
int retval;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.flags = 0,
.len = length,
.buf = buffer.write,
}
};
retval = do_i2c_transfer(client, msg);
return retval;
}
static void traverse_report_descriptor(unsigned int *index)
{
unsigned char size;
unsigned char *buf = buffer.read;
size = buf[*index] & MASK_2BIT;
switch (size) {
case 0: /* 0 bytes */
*index += 1;
break;
case 1: /* 1 byte */
*index += 2;
break;
case 2: /* 2 bytes */
*index += 3;
break;
case 3: /* 4 bytes */
*index += 5;
break;
default:
break;
}
}
static void find_blob_size(unsigned int index)
{
unsigned int ii = index;
unsigned char *buf = buffer.read;
while (ii < hid_dd.report_descriptor_length) {
if (buf[ii] == PREFIX_REPORT_COUNT_1BYTE) {
hid_report.blob_size = buf[ii + 1];
return;
} else if (buf[ii] == PREFIX_REPORT_COUNT_2BYTES) {
hid_report.blob_size = buf[ii + 1] | (buf[ii + 2] << 8);
return;
}
traverse_report_descriptor(&ii);
}
}
static void find_reports(unsigned int index)
{
unsigned int ii = index;
unsigned char *buf = buffer.read;
static unsigned int report_id_index;
static unsigned char report_id;
static unsigned short usage_page;
if (buf[ii] == PREFIX_REPORT_ID) {
report_id = buf[ii + 1];
report_id_index = ii;
return;
}
if (buf[ii] == PREFIX_USAGE_PAGE_1BYTE) {
usage_page = buf[ii + 1];
return;
} else if (buf[ii] == PREFIX_USAGE_PAGE_2BYTES) {
usage_page = buf[ii + 1] | (buf[ii + 2] << 8);
return;
}
if ((usage_page == VENDOR_DEFINED_PAGE) && (buf[ii] == PREFIX_USAGE)) {
switch (buf[ii + 1]) {
case USAGE_GET_BLOB:
hid_report.get_blob_id = report_id;
find_blob_size(report_id_index);
break;
case USAGE_WRITE:
hid_report.write_id = report_id;
break;
case USAGE_READ_ADDRESS:
hid_report.read_addr_id = report_id;
break;
case USAGE_READ_DATA:
hid_report.read_data_id = report_id;
break;
case USAGE_SET_MODE:
hid_report.set_mode_id = report_id;
break;
default:
break;
}
}
}
static int parse_report_descriptor(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned int ii = 0;
unsigned char *buf;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
buffer.write[0] = hid_dd.report_descriptor_index & MASK_8BIT;
buffer.write[1] = hid_dd.report_descriptor_index >> 8;
retval = generic_write(i2c, 2);
if (retval < 0)
return retval;
retval = generic_read(i2c, hid_dd.report_descriptor_length);
if (retval < 0)
return retval;
buf = buffer.read;
hid_report.get_blob_id = REPORT_ID_GET_BLOB;
hid_report.write_id = REPORT_ID_WRITE;
hid_report.read_addr_id = REPORT_ID_READ_ADDRESS;
hid_report.read_data_id = REPORT_ID_READ_DATA;
hid_report.set_mode_id = REPORT_ID_SET_RMI_MODE;
hid_report.blob_size = BLOB_REPORT_SIZE;
while (ii < hid_dd.report_descriptor_length) {
find_reports(ii);
traverse_report_descriptor(&ii);
}
return 0;
}
static int switch_to_rmi(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
check_buffer(&buffer.write, &buffer.write_size, 11);
/* set rmi mode */
buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.command_register_index >> 8;
buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id;
buffer.write[3] = SET_REPORT_COMMAND;
buffer.write[4] = hid_report.set_mode_id;
buffer.write[5] = hid_dd.data_register_index & MASK_8BIT;
buffer.write[6] = hid_dd.data_register_index >> 8;
buffer.write[7] = 0x04;
buffer.write[8] = 0x00;
buffer.write[9] = hid_report.set_mode_id;
buffer.write[10] = RMI_MODE;
retval = generic_write(i2c, 11);
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
static int check_report_mode(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned short report_size;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
check_buffer(&buffer.write, &buffer.write_size, 7);
buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.command_register_index >> 8;
buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id;
buffer.write[3] = GET_REPORT_COMMAND;
buffer.write[4] = hid_report.set_mode_id;
buffer.write[5] = hid_dd.data_register_index & MASK_8BIT;
buffer.write[6] = hid_dd.data_register_index >> 8;
retval = generic_write(i2c, 7);
if (retval < 0)
goto exit;
retval = generic_read(i2c, 2);
if (retval < 0)
goto exit;
report_size = (buffer.read[1] << 8) | buffer.read[0];
retval = generic_write(i2c, 7);
if (retval < 0)
goto exit;
retval = generic_read(i2c, report_size);
if (retval < 0)
goto exit;
retval = buffer.read[3];
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Report mode = %d\n",
__func__, retval);
exit:
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
static int hid_i2c_init(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
const struct synaptics_dsx_board_data *bdata =
rmi4_data->hw_if->board_data;
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
check_buffer(&buffer.write, &buffer.write_size, 6);
/* read device descriptor */
buffer.write[0] = bdata->device_descriptor_addr & MASK_8BIT;
buffer.write[1] = bdata->device_descriptor_addr >> 8;
retval = generic_write(i2c, 2);
if (retval < 0)
goto exit;
retval = generic_read(i2c, sizeof(hid_dd));
if (retval < 0)
goto exit;
retval = secure_memcpy((unsigned char *)&hid_dd,
sizeof(struct hid_device_descriptor),
buffer.read,
buffer.read_size,
sizeof(hid_dd));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy device descriptor data\n",
__func__);
goto exit;
}
retval = parse_report_descriptor(rmi4_data);
if (retval < 0)
goto exit;
/* set power */
buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.command_register_index >> 8;
buffer.write[2] = 0x00;
buffer.write[3] = SET_POWER_COMMAND;
retval = generic_write(i2c, 4);
if (retval < 0)
goto exit;
/* reset */
buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.command_register_index >> 8;
buffer.write[2] = 0x00;
buffer.write[3] = RESET_COMMAND;
retval = generic_write(i2c, 4);
if (retval < 0)
goto exit;
while (gpio_get_value(bdata->irq_gpio))
msleep(20);
retval = generic_read(i2c, hid_dd.input_report_max_length);
if (retval < 0)
goto exit;
/* get blob */
buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.command_register_index >> 8;
buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.get_blob_id;
buffer.write[3] = 0x02;
buffer.write[4] = hid_dd.data_register_index & MASK_8BIT;
buffer.write[5] = hid_dd.data_register_index >> 8;
retval = generic_write(i2c, 6);
if (retval < 0)
goto exit;
msleep(20);
retval = generic_read(i2c, hid_report.blob_size + 3);
if (retval < 0)
goto exit;
exit:
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to initialize HID/I2C interface\n",
__func__);
return retval;
}
retval = switch_to_rmi(rmi4_data);
return retval;
}
static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned char retry;
unsigned char recover = 1;
unsigned short report_length;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_msg msg[] = {
{
.addr = i2c->addr,
.flags = 0,
.len = hid_dd.output_report_max_length + 2,
},
{
.addr = i2c->addr,
.flags = I2C_M_RD,
.len = (unsigned short)(length + 4),
},
};
recover:
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
check_buffer(&buffer.write, &buffer.write_size,
hid_dd.output_report_max_length + 2);
msg[0].buf = buffer.write;
buffer.write[0] = hid_dd.output_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.output_register_index >> 8;
buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT;
buffer.write[3] = hid_dd.output_report_max_length >> 8;
buffer.write[4] = hid_report.read_addr_id;
buffer.write[5] = 0x00;
buffer.write[6] = addr & MASK_8BIT;
buffer.write[7] = addr >> 8;
buffer.write[8] = (unsigned char)length;
buffer.write[9] = (unsigned char)(length >> 8);
check_buffer(&buffer.read, &buffer.read_size, length + 4);
msg[1].buf = buffer.read;
retval = do_i2c_transfer(i2c, &msg[0]);
if (retval != 0)
goto exit;
retry = 0;
do {
retval = do_i2c_transfer(i2c, &msg[1]);
if (retval == 0)
retval = length;
else
goto exit;
report_length = (buffer.read[1] << 8) | buffer.read[0];
if (report_length == hid_dd.input_report_max_length) {
retval = secure_memcpy(&data[0], length,
&buffer.read[4], buffer.read_size - 4,
length);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
} else {
retval = length;
}
goto exit;
}
msleep(20);
retry++;
} while (retry < SYN_I2C_RETRY_TIMES);
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to receive read report\n",
__func__);
retval = -EIO;
exit:
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
if ((retval != length) && (recover == 1)) {
recover = 0;
if (check_report_mode(rmi4_data) != RMI_MODE) {
retval = hid_i2c_init(rmi4_data);
if (retval == 0)
goto recover;
}
}
return retval;
}
static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned char recover = 1;
unsigned int msg_length;
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
struct i2c_msg msg[] = {
{
.addr = i2c->addr,
.flags = 0,
}
};
if ((length + 10) < (hid_dd.output_report_max_length + 2))
msg_length = hid_dd.output_report_max_length + 2;
else
msg_length = length + 10;
recover:
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
check_buffer(&buffer.write, &buffer.write_size, msg_length);
msg[0].len = (unsigned short)msg_length;
msg[0].buf = buffer.write;
buffer.write[0] = hid_dd.output_register_index & MASK_8BIT;
buffer.write[1] = hid_dd.output_register_index >> 8;
buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT;
buffer.write[3] = hid_dd.output_report_max_length >> 8;
buffer.write[4] = hid_report.write_id;
buffer.write[5] = 0x00;
buffer.write[6] = addr & MASK_8BIT;
buffer.write[7] = addr >> 8;
buffer.write[8] = (unsigned char)length;
buffer.write[9] = (unsigned char)(length >> 8);
retval = secure_memcpy(&buffer.write[10], buffer.write_size - 10,
&data[0], length, length);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
} else {
retval = do_i2c_transfer(i2c, msg);
if (retval == 0)
retval = length;
}
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
if ((retval != length) && (recover == 1)) {
recover = 0;
if (check_report_mode(rmi4_data) != RMI_MODE) {
retval = hid_i2c_init(rmi4_data);
if (retval == 0)
goto recover;
}
}
return retval;
}
static struct synaptics_dsx_bus_access bus_access = {
.type = BUS_I2C,
.read = synaptics_rmi4_i2c_read,
.write = synaptics_rmi4_i2c_write,
};
static struct synaptics_dsx_hw_interface hw_if;
static struct platform_device *synaptics_dsx_i2c_device;
static void synaptics_rmi4_i2c_dev_release(struct device *dev)
{
kfree(synaptics_dsx_i2c_device);
}
static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int retval;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
"%s: SMBus byte data commands not supported by host\n",
__func__);
return -EIO;
}
synaptics_dsx_i2c_device = kzalloc(
sizeof(struct platform_device),
GFP_KERNEL);
if (!synaptics_dsx_i2c_device) {
dev_err(&client->dev,
"%s: Failed to allocate memory for synaptics_dsx_i2c_device\n",
__func__);
return -ENOMEM;
}
#ifdef CONFIG_OF
if (client->dev.of_node) {
hw_if.board_data = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_board_data),
GFP_KERNEL);
if (!hw_if.board_data) {
dev_err(&client->dev,
"%s: Failed to allocate memory for board data\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->cap_button_map) {
dev_err(&client->dev,
"%s: Failed to allocate memory for 0D button map\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->vir_button_map) {
dev_err(&client->dev,
"%s: Failed to allocate memory for virtual button map\n",
__func__);
return -ENOMEM;
}
parse_dt(&client->dev, hw_if.board_data);
}
#else
hw_if.board_data = client->dev.platform_data;
#endif
hw_if.bus_access = &bus_access;
hw_if.bl_hw_init = switch_to_rmi;
hw_if.ui_hw_init = hid_i2c_init;
synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
synaptics_dsx_i2c_device->id = 0;
synaptics_dsx_i2c_device->num_resources = 0;
synaptics_dsx_i2c_device->dev.parent = &client->dev;
synaptics_dsx_i2c_device->dev.platform_data = &hw_if;
synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release;
retval = platform_device_register(synaptics_dsx_i2c_device);
if (retval) {
dev_err(&client->dev,
"%s: Failed to register platform device\n",
__func__);
return -ENODEV;
}
return 0;
}
static int synaptics_rmi4_i2c_remove(struct i2c_client *client)
{
if (buffer.read_size)
kfree(buffer.read);
if (buffer.write_size)
kfree(buffer.write);
platform_device_unregister(synaptics_dsx_i2c_device);
return 0;
}
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
{I2C_DRIVER_NAME, 0},
{},
};
MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
#ifdef CONFIG_OF
static const struct of_device_id synaptics_rmi4_of_match_table[] = {
{
.compatible = "synaptics,dsx-rmi-hid-i2c",
},
{},
};
MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
#else
#define synaptics_rmi4_of_match_table NULL
#endif
static struct i2c_driver synaptics_rmi4_i2c_driver = {
.driver = {
.name = I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = synaptics_rmi4_of_match_table,
},
.probe = synaptics_rmi4_i2c_probe,
.remove = synaptics_rmi4_i2c_remove,
.id_table = synaptics_rmi4_id_table,
};
int synaptics_rmi4_bus_init(void)
{
return i2c_add_driver(&synaptics_rmi4_i2c_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_init);
void synaptics_rmi4_bus_exit(void)
{
i2c_del_driver(&synaptics_rmi4_i2c_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,698 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/types.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#define SPI_READ 0x80
#define SPI_WRITE 0x00
static unsigned char *buf;
static struct spi_transfer *xfer;
#ifdef CONFIG_OF
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
{
int retval;
u32 value;
const char *name;
struct property *prop;
struct device_node *np = dev->of_node;
bdata->irq_gpio = of_get_named_gpio_flags(np,
"synaptics,irq-gpio", 0,
(enum of_gpio_flags *)&bdata->irq_flags);
retval = of_property_read_u32(np, "synaptics,irq-on-state",
&value);
if (retval < 0)
bdata->irq_on_state = 0;
else
bdata->irq_on_state = value;
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
if (retval < 0)
bdata->pwr_reg_name = NULL;
else
bdata->pwr_reg_name = name;
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
if (retval < 0)
bdata->bus_reg_name = NULL;
else
bdata->bus_reg_name = name;
prop = of_find_property(np, "synaptics,power-gpio", NULL);
if (prop && prop->length) {
bdata->power_gpio = of_get_named_gpio_flags(np,
"synaptics,power-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,power-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
__func__);
return retval;
}
bdata->power_on_state = value;
} else {
bdata->power_gpio = -1;
}
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
__func__);
return retval;
}
bdata->power_delay_ms = value;
} else {
bdata->power_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
if (prop && prop->length) {
bdata->reset_gpio = of_get_named_gpio_flags(np,
"synaptics,reset-gpio", 0, NULL);
retval = of_property_read_u32(np, "synaptics,reset-on-state",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
__func__);
return retval;
}
bdata->reset_on_state = value;
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
__func__);
return retval;
}
bdata->reset_active_ms = value;
} else {
bdata->reset_gpio = -1;
}
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
__func__);
return retval;
}
bdata->reset_delay_ms = value;
} else {
bdata->reset_delay_ms = 0;
}
prop = of_find_property(np, "synaptics,byte-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,byte-delay-us",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,byte-delay-us property\n",
__func__);
return retval;
}
bdata->byte_delay_us = value;
} else {
bdata->byte_delay_us = 0;
}
prop = of_find_property(np, "synaptics,block-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,block-delay-us",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,block-delay-us property\n",
__func__);
return retval;
}
bdata->block_delay_us = value;
} else {
bdata->block_delay_us = 0;
}
prop = of_find_property(np, "synaptics,address-delay-us", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,address-delay-us",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,address-delay-us property\n",
__func__);
return retval;
}
bdata->addr_delay_us = value;
} else {
bdata->addr_delay_us = 0;
}
prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
__func__);
return retval;
}
bdata->max_y_for_2d = value;
} else {
bdata->max_y_for_2d = -1;
}
prop = of_find_property(np, "synaptics,swap-axes", NULL);
bdata->swap_axes = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,x-flip", NULL);
bdata->x_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,y-flip", NULL);
bdata->y_flip = prop > 0 ? true : false;
prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
if (prop && prop->length) {
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
&value);
if (retval < 0) {
dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
__func__);
return retval;
}
bdata->ub_i2c_addr = (unsigned short)value;
} else {
bdata->ub_i2c_addr = -1;
}
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
if (prop && prop->length) {
bdata->cap_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->cap_button_map->map)
return -ENOMEM;
bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
retval = of_property_read_u32_array(np,
"synaptics,cap-button-codes",
bdata->cap_button_map->map,
bdata->cap_button_map->nbuttons);
if (retval < 0) {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
} else {
bdata->cap_button_map->nbuttons = 0;
bdata->cap_button_map->map = NULL;
}
prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
if (prop && prop->length) {
bdata->vir_button_map->map = devm_kzalloc(dev,
prop->length,
GFP_KERNEL);
if (!bdata->vir_button_map->map)
return -ENOMEM;
bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
bdata->vir_button_map->nbuttons /= 5;
retval = of_property_read_u32_array(np,
"synaptics,vir-button-codes",
bdata->vir_button_map->map,
bdata->vir_button_map->nbuttons * 5);
if (retval < 0) {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
} else {
bdata->vir_button_map->nbuttons = 0;
bdata->vir_button_map->map = NULL;
}
return 0;
}
#endif
static int synaptics_rmi4_spi_alloc_buf(struct synaptics_rmi4_data *rmi4_data,
unsigned int size, unsigned int count)
{
static unsigned int buf_size;
static unsigned int xfer_count;
if (size > buf_size) {
if (buf_size)
kfree(buf);
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for buf\n",
__func__);
buf_size = 0;
return -ENOMEM;
}
buf_size = size;
}
if (count > xfer_count) {
if (xfer_count)
kfree(xfer);
xfer = kcalloc(count, sizeof(struct spi_transfer), GFP_KERNEL);
if (!xfer) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for xfer\n",
__func__);
xfer_count = 0;
return -ENOMEM;
}
xfer_count = count;
} else {
memset(xfer, 0, count * sizeof(struct spi_transfer));
}
return 0;
}
static int synaptics_rmi4_spi_set_page(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr)
{
int retval;
unsigned int index;
unsigned int byte_count = PAGE_SELECT_LEN + 1;
unsigned char page;
struct spi_message msg;
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
const struct synaptics_dsx_board_data *bdata =
rmi4_data->hw_if->board_data;
page = ((addr >> 8) & MASK_8BIT);
if ((page >> 7) == (rmi4_data->current_page >> 7))
return PAGE_SELECT_LEN;
spi_message_init(&msg);
retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count,
byte_count);
if (retval < 0)
return retval;
buf[0] = SPI_WRITE;
buf[1] = MASK_8BIT;
buf[2] = page;
if (bdata->byte_delay_us == 0) {
xfer[0].len = byte_count;
xfer[0].tx_buf = &buf[0];
if (bdata->block_delay_us)
xfer[0].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[0], &msg);
} else {
for (index = 0; index < byte_count; index++) {
xfer[index].len = 1;
xfer[index].tx_buf = &buf[index];
if (index == 1)
xfer[index].delay_usecs = bdata->addr_delay_us;
else
xfer[index].delay_usecs = bdata->byte_delay_us;
spi_message_add_tail(&xfer[index], &msg);
}
if (bdata->block_delay_us)
xfer[index - 1].delay_usecs = bdata->block_delay_us;
}
retval = spi_sync(spi, &msg);
if (retval == 0) {
rmi4_data->current_page = page;
retval = PAGE_SELECT_LEN;
} else {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to complete SPI transfer, error = %d\n",
__func__, retval);
}
return retval;
}
static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned int index;
unsigned int byte_count = length + ADDRESS_LEN;
unsigned char txbuf[ADDRESS_LEN];
struct spi_message msg;
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
const struct synaptics_dsx_board_data *bdata =
rmi4_data->hw_if->board_data;
spi_message_init(&msg);
txbuf[0] = (addr >> 8) | SPI_READ;
txbuf[1] = addr & MASK_8BIT;
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
if (retval != PAGE_SELECT_LEN) {
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return -EIO;
}
if (bdata->byte_delay_us == 0) {
retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, length,
2);
} else {
retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, length,
byte_count);
}
if (retval < 0) {
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
if (bdata->byte_delay_us == 0) {
xfer[0].len = ADDRESS_LEN;
xfer[0].tx_buf = &txbuf[0];
spi_message_add_tail(&xfer[0], &msg);
xfer[1].len = length;
xfer[1].rx_buf = &buf[0];
if (bdata->block_delay_us)
xfer[1].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(&xfer[1], &msg);
} else {
for (index = 0; index < byte_count; index++) {
xfer[index].len = 1;
if (index < ADDRESS_LEN)
xfer[index].tx_buf = &txbuf[index];
else
xfer[index].rx_buf = &buf[index - ADDRESS_LEN];
if (index == 1)
xfer[index].delay_usecs = bdata->addr_delay_us;
else
xfer[index].delay_usecs = bdata->byte_delay_us;
spi_message_add_tail(&xfer[index], &msg);
}
if (bdata->block_delay_us)
xfer[index - 1].delay_usecs = bdata->block_delay_us;
}
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = secure_memcpy(data, length, buf, length, length);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
} else {
retval = length;
}
} else {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to complete SPI transfer, error = %d\n",
__func__, retval);
}
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data,
unsigned short addr, unsigned char *data, unsigned int length)
{
int retval;
unsigned int index;
unsigned int byte_count = length + ADDRESS_LEN;
struct spi_message msg;
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
const struct synaptics_dsx_board_data *bdata =
rmi4_data->hw_if->board_data;
spi_message_init(&msg);
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
if (retval != PAGE_SELECT_LEN) {
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return -EIO;
}
if (bdata->byte_delay_us == 0) {
retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count,
1);
} else {
retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count,
byte_count);
}
if (retval < 0) {
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
buf[0] = (addr >> 8) & ~SPI_READ;
buf[1] = addr & MASK_8BIT;
retval = secure_memcpy(&buf[ADDRESS_LEN],
byte_count - ADDRESS_LEN, data, length, length);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to copy data\n",
__func__);
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
if (bdata->byte_delay_us == 0) {
xfer[0].len = byte_count;
xfer[0].tx_buf = &buf[0];
if (bdata->block_delay_us)
xfer[0].delay_usecs = bdata->block_delay_us;
spi_message_add_tail(xfer, &msg);
} else {
for (index = 0; index < byte_count; index++) {
xfer[index].len = 1;
xfer[index].tx_buf = &buf[index];
if (index == 1)
xfer[index].delay_usecs = bdata->addr_delay_us;
else
xfer[index].delay_usecs = bdata->byte_delay_us;
spi_message_add_tail(&xfer[index], &msg);
}
if (bdata->block_delay_us)
xfer[index - 1].delay_usecs = bdata->block_delay_us;
}
retval = spi_sync(spi, &msg);
if (retval == 0) {
retval = length;
} else {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to complete SPI transfer, error = %d\n",
__func__, retval);
}
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
return retval;
}
static struct synaptics_dsx_bus_access bus_access = {
.type = BUS_SPI,
.read = synaptics_rmi4_spi_read,
.write = synaptics_rmi4_spi_write,
};
static struct synaptics_dsx_hw_interface hw_if;
static struct platform_device *synaptics_dsx_spi_device;
static void synaptics_rmi4_spi_dev_release(struct device *dev)
{
kfree(synaptics_dsx_spi_device);
}
static int synaptics_rmi4_spi_probe(struct spi_device *spi)
{
int retval;
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
dev_err(&spi->dev,
"%s: Full duplex not supported by host\n",
__func__);
return -EIO;
}
synaptics_dsx_spi_device = kzalloc(
sizeof(struct platform_device),
GFP_KERNEL);
if (!synaptics_dsx_spi_device) {
dev_err(&spi->dev,
"%s: Failed to allocate memory for synaptics_dsx_spi_device\n",
__func__);
return -ENOMEM;
}
#ifdef CONFIG_OF
if (spi->dev.of_node) {
hw_if.board_data = devm_kzalloc(&spi->dev,
sizeof(struct synaptics_dsx_board_data),
GFP_KERNEL);
if (!hw_if.board_data) {
dev_err(&spi->dev,
"%s: Failed to allocate memory for board data\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->cap_button_map = devm_kzalloc(&spi->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->cap_button_map) {
dev_err(&spi->dev,
"%s: Failed to allocate memory for 0D button map\n",
__func__);
return -ENOMEM;
}
hw_if.board_data->vir_button_map = devm_kzalloc(&spi->dev,
sizeof(struct synaptics_dsx_button_map),
GFP_KERNEL);
if (!hw_if.board_data->vir_button_map) {
dev_err(&spi->dev,
"%s: Failed to allocate memory for virtual button map\n",
__func__);
return -ENOMEM;
}
parse_dt(&spi->dev, hw_if.board_data);
}
#else
hw_if.board_data = spi->dev.platform_data;
#endif
hw_if.bus_access = &bus_access;
spi->bits_per_word = 8;
spi->mode = SPI_MODE_3;
retval = spi_setup(spi);
if (retval < 0) {
dev_err(&spi->dev,
"%s: Failed to perform SPI setup\n",
__func__);
return retval;
}
synaptics_dsx_spi_device->name = PLATFORM_DRIVER_NAME;
synaptics_dsx_spi_device->id = 0;
synaptics_dsx_spi_device->num_resources = 0;
synaptics_dsx_spi_device->dev.parent = &spi->dev;
synaptics_dsx_spi_device->dev.platform_data = &hw_if;
synaptics_dsx_spi_device->dev.release = synaptics_rmi4_spi_dev_release;
retval = platform_device_register(synaptics_dsx_spi_device);
if (retval) {
dev_err(&spi->dev,
"%s: Failed to register platform device\n",
__func__);
return -ENODEV;
}
return 0;
}
static int synaptics_rmi4_spi_remove(struct spi_device *spi)
{
platform_device_unregister(synaptics_dsx_spi_device);
return 0;
}
static const struct spi_device_id synaptics_rmi4_id_table[] = {
{SPI_DRIVER_NAME, 0},
{},
};
MODULE_DEVICE_TABLE(spi, synaptics_rmi4_id_table);
#ifdef CONFIG_OF
static const struct of_device_id synaptics_rmi4_of_match_table[] = {
{
.compatible = "synaptics,dsx-spi",
},
{},
};
MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
#else
#define synaptics_rmi4_of_match_table NULL
#endif
static struct spi_driver synaptics_rmi4_spi_driver = {
.driver = {
.name = SPI_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = synaptics_rmi4_of_match_table,
},
.probe = synaptics_rmi4_spi_probe,
.remove = synaptics_rmi4_spi_remove,
.id_table = synaptics_rmi4_id_table,
};
int synaptics_rmi4_bus_init(void)
{
return spi_register_driver(&synaptics_rmi4_spi_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_init);
void synaptics_rmi4_bus_exit(void)
{
kfree(buf);
kfree(xfer);
spi_unregister_driver(&synaptics_rmi4_spi_driver);
}
EXPORT_SYMBOL(synaptics_rmi4_bus_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX SPI Bus Support Module");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,403 @@
/*
* Synaptics DSX touchscreen driver
*
* Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved.
*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
* DOLLARS.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/input/synaptics_dsx.h>
#include "synaptics_dsx_core.h"
#define SYSFS_FOLDER_NAME "video"
static ssize_t video_sysfs_dcs_write_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
static ssize_t video_sysfs_param_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
static int video_send_dcs_command(unsigned char command_opcode);
struct f38_command {
union {
struct {
unsigned char command_opcode;
unsigned char register_access:1;
unsigned char gamma_page:1;
unsigned char f38_control1_b2__7:6;
unsigned char parameter_field_1;
unsigned char parameter_field_2;
unsigned char parameter_field_3;
unsigned char parameter_field_4;
unsigned char send_to_dcs:1;
unsigned char f38_command6_b1__7:7;
} __packed;
unsigned char data[7];
};
};
struct synaptics_rmi4_video_handle {
unsigned char param;
unsigned short query_base_addr;
unsigned short control_base_addr;
unsigned short data_base_addr;
unsigned short command_base_addr;
struct synaptics_rmi4_data *rmi4_data;
struct kobject *sysfs_dir;
};
#ifdef RMI_DCS_SUSPEND_RESUME
struct dcs_command {
unsigned char command;
unsigned int wait_time;
};
static struct dcs_command suspend_sequence[] = {
{
.command = 0x28,
.wait_time = 200,
},
{
.command = 0x10,
.wait_time = 200,
},
};
static struct dcs_command resume_sequence[] = {
{
.command = 0x11,
.wait_time = 200,
},
{
.command = 0x29,
.wait_time = 200,
},
};
#endif
static struct device_attribute attrs[] = {
__ATTR(dcs_write, 0220,
synaptics_rmi4_show_error,
video_sysfs_dcs_write_store),
__ATTR(param, 0220,
synaptics_rmi4_show_error,
video_sysfs_param_store),
};
static struct synaptics_rmi4_video_handle *video;
DECLARE_COMPLETION(video_remove_complete);
static ssize_t video_sysfs_dcs_write_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int retval;
unsigned int input;
if (kstrtouint(buf, 16, &input) != 1)
return -EINVAL;
retval = video_send_dcs_command((unsigned char)input);
if (retval < 0)
return retval;
return count;
}
static ssize_t video_sysfs_param_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned int input;
if (kstrtouint(buf, 16, &input) != 1)
return -EINVAL;
video->param = (unsigned char)input;
return count;
}
static int video_send_dcs_command(unsigned char command_opcode)
{
int retval;
struct f38_command command;
struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
memset(&command, 0x00, sizeof(command));
command.command_opcode = command_opcode;
command.parameter_field_1 = video->param;
command.send_to_dcs = 1;
video->param = 0;
retval = synaptics_rmi4_reg_write(rmi4_data,
video->command_base_addr,
command.data,
sizeof(command.data));
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to send DCS command\n",
__func__);
return retval;
}
return 0;
}
static int video_scan_pdt(void)
{
int retval;
unsigned char page;
unsigned short addr;
bool f38_found = false;
struct synaptics_rmi4_fn_desc rmi_fd;
struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
for (page = 0; page < PAGES_TO_SERVICE; page++) {
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
addr |= (page << 8);
retval = synaptics_rmi4_reg_read(rmi4_data,
addr,
(unsigned char *)&rmi_fd,
sizeof(rmi_fd));
if (retval < 0)
return retval;
addr &= ~(MASK_8BIT << 8);
if (!rmi_fd.fn_number)
break;
if (rmi_fd.fn_number == SYNAPTICS_RMI4_F38) {
f38_found = true;
goto f38_found;
}
}
}
if (!f38_found) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to find F38\n",
__func__);
return -EINVAL;
}
f38_found:
video->query_base_addr = rmi_fd.query_base_addr | (page << 8);
video->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8);
video->data_base_addr = rmi_fd.data_base_addr | (page << 8);
video->command_base_addr = rmi_fd.cmd_base_addr | (page << 8);
return 0;
}
static int synaptics_rmi4_video_init(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned char attr_count;
if (video) {
dev_dbg(rmi4_data->pdev->dev.parent,
"%s: Handle already exists\n",
__func__);
return 0;
}
video = kzalloc(sizeof(*video), GFP_KERNEL);
if (!video) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for video\n",
__func__);
retval = -ENOMEM;
goto exit;
}
video->rmi4_data = rmi4_data;
retval = video_scan_pdt();
if (retval < 0) {
retval = 0;
goto exit_scan_pdt;
}
video->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
&rmi4_data->input_dev->dev.kobj);
if (!video->sysfs_dir) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to create sysfs directory\n",
__func__);
retval = -ENODEV;
goto exit_sysfs_dir;
}
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
retval = sysfs_create_file(video->sysfs_dir,
&attrs[attr_count].attr);
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to create sysfs attributes\n",
__func__);
retval = -ENODEV;
goto exit_sysfs_attrs;
}
}
return 0;
exit_sysfs_attrs:
for (attr_count--; attr_count >= 0; attr_count--)
sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
kobject_put(video->sysfs_dir);
exit_sysfs_dir:
exit_scan_pdt:
kfree(video);
video = NULL;
exit:
return retval;
}
static void synaptics_rmi4_video_remove(struct synaptics_rmi4_data *rmi4_data)
{
unsigned char attr_count;
if (!video)
goto exit;
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
kobject_put(video->sysfs_dir);
kfree(video);
video = NULL;
exit:
complete(&video_remove_complete);
}
static void synaptics_rmi4_video_reset(struct synaptics_rmi4_data *rmi4_data)
{
if (!video)
synaptics_rmi4_video_init(rmi4_data);
}
#ifdef RMI_DCS_SUSPEND_RESUME
static void synaptics_rmi4_video_suspend(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned char ii;
unsigned char command;
unsigned char num_of_cmds;
if (!video)
return;
num_of_cmds = ARRAY_SIZE(suspend_sequence);
for (ii = 0; ii < num_of_cmds; ii++) {
command = suspend_sequence[ii].command;
retval = video_send_dcs_command(command);
if (retval < 0)
return;
msleep(suspend_sequence[ii].wait_time);
}
}
static void synaptics_rmi4_video_resume(struct synaptics_rmi4_data *rmi4_data)
{
int retval;
unsigned char ii;
unsigned char command;
unsigned char num_of_cmds;
if (!video)
return;
num_of_cmds = ARRAY_SIZE(resume_sequence);
for (ii = 0; ii < num_of_cmds; ii++) {
command = resume_sequence[ii].command;
retval = video_send_dcs_command(command);
if (retval < 0)
return;
msleep(resume_sequence[ii].wait_time);
}
}
#endif
static struct synaptics_rmi4_exp_fn video_module = {
.fn_type = RMI_VIDEO,
.init = synaptics_rmi4_video_init,
.remove = synaptics_rmi4_video_remove,
.reset = synaptics_rmi4_video_reset,
.reinit = NULL,
.early_suspend = NULL,
#ifdef RMI_DCS_SUSPEND_RESUME
.suspend = synaptics_rmi4_video_suspend,
.resume = synaptics_rmi4_video_resume,
#else
.suspend = NULL,
.resume = NULL,
#endif
.late_resume = NULL,
.attn = NULL,
};
static int __init rmi4_video_module_init(void)
{
synaptics_rmi4_new_function(&video_module, true);
return 0;
}
static void __exit rmi4_video_module_exit(void)
{
synaptics_rmi4_new_function(&video_module, false);
wait_for_completion(&video_remove_complete);
}
module_init(rmi4_video_module_init);
module_exit(rmi4_video_module_exit);
MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("Synaptics DSX Video Module");
MODULE_LICENSE("GPL v2");