From 4f75f1bd8b3203bc429f9d6178f0ebe55923a12f Mon Sep 17 00:00:00 2001 From: Sunny Luo Date: Thu, 18 Jan 2018 14:08:22 +0800 Subject: [PATCH] PD#158972: touchscreen: focaltech ft3x27 driver support Change-Id: I5e1de4a6074a75c288d52fd388323978415610bd Signed-off-by: Sunny Luo --- .../bindings/input/touchscreen/amlogic-ts.txt | 28 + MAINTAINERS | 6 + arch/arm64/configs/meson64_defconfig | 2 + drivers/amlogic/input/Kconfig | 2 + drivers/amlogic/input/Makefile | 2 + drivers/amlogic/input/touchscreen/Kconfig | 22 + drivers/amlogic/input/touchscreen/Makefile | 7 + .../input/touchscreen/focaltech_touch/Kconfig | 17 + .../touchscreen/focaltech_touch/Makefile | 17 + .../focaltech_touch/focaltech_common.h | 196 +++ .../focaltech_touch/focaltech_config.h | 228 +++ .../focaltech_touch/focaltech_core.c | 1500 +++++++++++++++++ .../focaltech_touch/focaltech_core.h | 194 +++ .../focaltech_touch/focaltech_esdcheck.c | 491 ++++++ .../focaltech_touch/focaltech_ex_fun.c | 1351 +++++++++++++++ .../focaltech_touch/focaltech_ex_mode.c | 376 +++++ .../focaltech_touch/focaltech_flash.c | 860 ++++++++++ .../focaltech_touch/focaltech_flash.h | 120 ++ .../focaltech_touch/focaltech_flash/Makefile | 10 + .../focaltech_upgrade_common.h | 56 + .../focaltech_upgrade_ft7250.c | 1350 +++++++++++++++ .../focaltech_flash/focaltech_upgrade_idc.c | 461 +++++ .../focaltech_flash/focaltech_upgrade_test.c | 179 ++ .../focaltech_touch/focaltech_gesture.c | 670 ++++++++ .../focaltech_touch/focaltech_i2c.c | 216 +++ .../focaltech_point_report_check.c | 153 ++ .../focaltech_touch/focaltech_sensor.c | 329 ++++ 27 files changed, 8843 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/amlogic-ts.txt create mode 100755 drivers/amlogic/input/touchscreen/Kconfig create mode 100755 drivers/amlogic/input/touchscreen/Makefile create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/Kconfig create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/Makefile create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_common.h create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_config.h create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.h create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_esdcheck.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_fun.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_mode.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.h create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/Makefile create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7250.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_gesture.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_i2c.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_point_report_check.c create mode 100755 drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_sensor.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/amlogic-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/amlogic-ts.txt new file mode 100644 index 000000000000..4435ebb0609e --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/amlogic-ts.txt @@ -0,0 +1,28 @@ +* Focaltech FT3x27 series touchscreen controller + +Required properties: + - compatible: Should be "focaltech,fts" + - reg: I2C address of the chip. Should be 0x38 + - irq-gpio: GPIO pin used for IRQ + - reset-gpio: GPIO pin used for reset + - x_max: horizontal resolution + - y_max: vertical resolution + - max-touch-number: the max touch fingers support + +Example: + i2c1: i2c@1e000 { + /* ... */ + + focaltech_ts@0x38 { + compatible = "focaltech,fts"; + status = "okay"; + reg = <0x38>; + reset-gpio = <&gpio GPIOZ_2 0x00>; + irq-gpio = <&gpio GPIOZ_3 0x00>; + x_max = <600>; + y_max = <1024>; + max-touch-number = <10>; + }; + + /* ... */ + }; diff --git a/MAINTAINERS b/MAINTAINERS index 597ece49f365..99b0fc84ca16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14250,3 +14250,9 @@ AMLOGIC LEDRING DRIVER IOCTL M: Renjun Xu F: drivers/amlogic/ledring/aml-is31fl32xx.c F: drivers/amlogic/ledring/aml-pca9557.c + +AMLOGIC TOUCHSCREEN DRIVER +M: Sunny Luo +F: Documentation/devicetree/bindings/input/touchscreen/amlogic-ts.txt +F: drivers/amlogic/input/touchscreen/* +F: drivers/amlogic/input/touchscreen/focaltech_touch/* diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 28475890ce2d..69c06753ca48 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -234,6 +234,8 @@ CONFIG_AMLOGIC_ADC_KEYPADS=y CONFIG_AMLOGIC_GPIO_KEY=y CONFIG_AMLOGIC_REMOTE=y CONFIG_AMLOGIC_MESON_REMOTE=y +CONFIG_AMLOGIC_TOUCHSCREEN=y +CONFIG_AMLOGIC_TOUCHSCREEN_FTS=y CONFIG_AMLOGIC_EFUSE=y CONFIG_AMLOGIC_REBOOT=y CONFIG_AMLOGIC_GX_REBOOT=y diff --git a/drivers/amlogic/input/Kconfig b/drivers/amlogic/input/Kconfig index a155d4af3e65..01bb95699043 100644 --- a/drivers/amlogic/input/Kconfig +++ b/drivers/amlogic/input/Kconfig @@ -13,5 +13,7 @@ if AMLOGIC_INPUT source "drivers/amlogic/input/keyboard/Kconfig" source "drivers/amlogic/input/remote/Kconfig" + +source "drivers/amlogic/input/touchscreen/Kconfig" endif diff --git a/drivers/amlogic/input/Makefile b/drivers/amlogic/input/Makefile index 87fc1ae2ff65..ec30b73cdc79 100644 --- a/drivers/amlogic/input/Makefile +++ b/drivers/amlogic/input/Makefile @@ -7,3 +7,5 @@ obj-$(CONFIG_AMLOGIC_INPUT_KEYBOARD) += keyboard/ obj-$(CONFIG_AMLOGIC_REMOTE) += remote/ + +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN) += touchscreen/ diff --git a/drivers/amlogic/input/touchscreen/Kconfig b/drivers/amlogic/input/touchscreen/Kconfig new file mode 100755 index 000000000000..52cee1cc3450 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/Kconfig @@ -0,0 +1,22 @@ +# +# touchscreen drivers +# + +menuconfig AMLOGIC_TOUCHSCREEN + bool "amlogic touchscreen" + default n + help + Say Y here, and a list of supported touchscreen driver will be displayed. + This option doesn't affect the kernel. + +if AMLOGIC_TOUCHSCREEN + +config AMLOGIC_TOUCHSCREEN_FTS + tristate "facaltech FT_xx touch driver support" + depends on I2C + default n + help + Say Y here if you want to use facaltech FT_xx. + + +endif diff --git a/drivers/amlogic/input/touchscreen/Makefile b/drivers/amlogic/input/touchscreen/Makefile new file mode 100755 index 000000000000..b0bb315f33ee --- /dev/null +++ b/drivers/amlogic/input/touchscreen/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for touchscreen drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_touch/ diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/Kconfig b/drivers/amlogic/input/touchscreen/focaltech_touch/Kconfig new file mode 100755 index 000000000000..2a1888232563 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/Kconfig @@ -0,0 +1,17 @@ +# +# Focaltech Touchscreen driver configuration +# + +config AMLOGIC_TOUCHSCREEN_FTS + bool "Focaltech Touchscreen" + depends on I2C + default n + help + Say Y here if you have Focaltech touch panel. + If unsure, say N. + +config AMLOGIC_TOUCHSCREEN_FTS_DIRECTORY + string "Focaltech ts directory name" + default "focaltech_touch" + depends on AMLOGIC_TOUCHSCREEN_FTS + \ No newline at end of file diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/Makefile b/drivers/amlogic/input/touchscreen/focaltech_touch/Makefile new file mode 100755 index 000000000000..669fa423eb63 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the focaltech touchscreen drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_core.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_ex_fun.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_ex_mode.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_flash.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_gesture.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_esdcheck.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_i2c.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_sensor.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_point_report_check.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_flash/ + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_common.h b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_common.h new file mode 100755 index 000000000000..b28f7810f793 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_common.h @@ -0,0 +1,196 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/***************************************************************************** +* +* File Name: focaltech_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 V1.4 20170630" + +#define FLAGBIT(x) (0x00000001 << (x)) +#define FLAGBITS(x, y) ((0xFFFFFFFF >> (32 - (y) - 1)) << (x)) + +#define FLAG_ICSERIALS_LEN 5 +#define FLAG_IDC_BIT 11 + +#define IC_SERIALS (FTS_CHIP_TYPE & FLAGBITS(0, FLAG_ICSERIALS_LEN-1)) +#define FTS_CHIP_IDC ((FTS_CHIP_TYPE & FLAGBIT(FLAG_IDC_BIT)) == FLAGBIT(FLAG_IDC_BIT)) + +#define FTS_CHIP_TYPE_MAPPING {{0x07,0x80, 0x06, 0x80, 0x06, 0x80, 0xC6, 0x80, 0xB6}} + +#define I2C_BUFFER_LENGTH_MAXINUM 256 +#define FILE_NAME_LENGTH 128 +#define ENABLE 1 +#define DISABLE 0 +/*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_CHIP_ID 0xA3 +#define FTS_REG_CHIP_ID2 0x9F +#define FTS_REG_POWER_MODE 0xA5 +#define FTS_REG_POWER_MODE_SLEEP_VALUE 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_GLOVE_MODE_EN 0xC0 +#define FTS_REG_COVER_MODE_EN 0xC1 +#define FTS_REG_CHARGER_MODE_EN 0x8B +#define FTS_REG_GESTURE_EN 0xD0 +#define FTS_REG_GESTURE_OUTPUT_ADDRESS 0xD3 +#define FTS_REG_ESD_SATURATE 0xED + + + +/***************************************************************************** +* 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 +{ + unsigned long type; + unsigned char chip_idh; + unsigned char chip_idl; + unsigned char rom_idh; + unsigned char rom_idl; + unsigned char pramboot_idh; + unsigned char pramboot_idl; + unsigned char bootloader_idh; + unsigned char bootloader_idl; +}; + +/* i2c communication*/ +int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue); +int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue); +int fts_i2c_read(struct i2c_client *client, char *writebuf,int writelen, char *readbuf, int readlen); +int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen); +int fts_i2c_init(void); +int fts_i2c_exit(void); + +/* Gesture functions */ +#if FTS_GESTURE_EN +int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client); +int fts_gesture_exit(struct i2c_client *client); +void fts_gesture_recovery(struct i2c_client *client); +int fts_gesture_readdata(struct i2c_client *client); +int fts_gesture_suspend(struct i2c_client *i2c_client); +int fts_gesture_resume(struct i2c_client *client); +#endif + +/* Apk and functions */ +#if FTS_APK_NODE_EN +int fts_create_apk_debug_channel(struct i2c_client * client); +void fts_release_apk_debug_channel(void); +#endif + +/* ADB functions */ +#if FTS_SYSFS_NODE_EN +int fts_create_sysfs(struct i2c_client *client); +int fts_remove_sysfs(struct i2c_client *client); +#endif + +/* ESD */ +#if FTS_ESDCHECK_EN +int fts_esdcheck_init(void); +int fts_esdcheck_exit(void); +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); +int fts_esdcheck_get_status(void); +#endif + +/* Point Report Check*/ +#if FTS_POINT_REPORT_CHECK_EN +int fts_point_report_check_init(void); +int fts_point_report_check_exit(void); +void fts_point_report_check_queue_work(void); +#endif + +/* Other */ +extern int g_show_log; +int fts_reset_proc(int hdelayms); +int fts_wait_tp_to_valid(struct i2c_client *client); +void fts_tp_state_recovery(struct i2c_client *client); +int fts_ex_mode_init(struct i2c_client *client); +int fts_ex_mode_exit(struct i2c_client *client); +int fts_ex_mode_recovery(struct i2c_client *client); + +void fts_irq_disable(void); +void fts_irq_enable(void); + +/***************************************************************************** +* DEBUG function define here +*****************************************************************************/ +#if FTS_DEBUG_EN +#define FTS_DEBUG_LEVEL 1 + +#if (FTS_DEBUG_LEVEL == 2) +#define FTS_DEBUG(fmt, args...) printk(KERN_ERR "[FTS][%s]"fmt"\n", __func__, ##args) +#else +#define FTS_DEBUG(fmt, args...) printk(KERN_ERR "[FTS]"fmt"\n", ##args) +#endif + +#define FTS_FUNC_ENTER() printk(KERN_ERR "[FTS]%s: Enter\n", __func__) +#define FTS_FUNC_EXIT() printk(KERN_ERR "[FTS]%s: Exit(%d)\n", __func__, __LINE__) +#else +#define FTS_DEBUG(fmt, args...) +#define FTS_FUNC_ENTER() +#define FTS_FUNC_EXIT() +#endif + +#define FTS_INFO(fmt, args...) do { \ + if (g_show_log) {printk(KERN_ERR "[FTS][Info]"fmt"\n", ##args);} \ + } while (0) + +#define FTS_ERROR(fmt, args...) do { \ + if (g_show_log) {printk(KERN_ERR "[FTS][Error]"fmt"\n", ##args);} \ + } while (0) + + +#endif /* __LINUX_FOCALTECH_COMMON_H__ */ + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_config.h b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_config.h new file mode 100755 index 000000000000..9d5dc38d7062 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_config.h @@ -0,0 +1,228 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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 _FT7250 0x72500807 +#define _FT8606 0x86060808 +#define _FT8607 0x86070809 +#define _FTE716 0xE716080a + +#define _FT5416 0x54160002 +#define _FT5426 0x54260002 +#define _FT5435 0x54350002 +#define _FT5436 0x54360002 +#define _FT5526 0x55260002 +#define _FT5526I 0x5526B002 +#define _FT5446 0x54460002 +#define _FT5346 0x53460002 +#define _FT5446I 0x5446B002 +#define _FT5346I 0x5346B002 +#define _FT7661 0x76610002 +#define _FT7511 0x75110002 +#define _FT7421 0x74210002 +#define _FT7681 0x76810002 +#define _FT3C47U 0x3C47D002 +#define _FT3417 0x34170002 +#define _FT3517 0x35170002 +#define _FT3327 0x33270002 +#define _FT3427 0x34270002 + +#define _FT5626 0x56260001 +#define _FT5726 0x57260001 +#define _FT5826B 0x5826B001 +#define _FT5826S 0x5826C001 +#define _FT7811 0x78110001 +#define _FT3D47 0x3D470001 +#define _FT3617 0x36170001 +#define _FT3717 0x37170001 +#define _FT3817B 0x3817B001 + +#define _FT6236U 0x6236D003 +#define _FT6336G 0x6336A003 +#define _FT6336U 0x6336D003 +#define _FT6436U 0x6436D003 + +#define _FT3267 0x32670004 +#define _FT3367 0x33670004 + + + +/*************************************************/ + +/* + * choose your ic chip type of focaltech + */ +#define FTS_CHIP_TYPE _FT7250 + +/******************* 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 + +/* + * Glove mode enable + * 1: enable, 0:disable(default) + */ +#define FTS_GLOVE_EN 0 +/* + * cover enable + * 1: enable, 0:disable(default) + */ +#define FTS_COVER_EN 0 +/* + * Charger enable + * 1: enable, 0:disable(default) + */ +#define FTS_CHARGER_EN 0 + +/* + * Proximity sensor + * default: disable + */ +#define FTS_PSENSOR_EN 0 + +/* + * Nodes for tools, please keep enable + */ +#define FTS_SYSFS_NODE_EN 1 +#define FTS_APK_NODE_EN 1 + +/* + * Customer power enable + * enable it when customer need control TP power + * default: disable + */ +#define FTS_POWER_SOURCE_CUST_EN 0 + +/****************************************************/ + +/********************** Upgrade ****************************/ +/* + * auto upgrade, please keep enable + */ +#define FTS_AUTO_UPGRADE_EN 1 + +/* + * auto upgrade for lcd cfg + * default: 0 + */ +#define FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN 1 + +/* auto cb check + * default: disable + */ +#define FTS_AUTO_CLB_EN 0 + +/* + * Check vendor_id number + * 0:No check vendor_id (default) + * 1/2/3: Check vendor_id for vendor compatibility + */ +#define FTS_GET_VENDOR_ID_NUM 0 + +/* + * vendor_id(s) for vendor(s) to be compatible with. + * a confirmation of vendor_id(s) is recommended. + * FTS_GET_VENDOR_ID_NUM == 0, no check vendor id, you may ignore them + * FTS_GET_VENDOR_ID_NUM >= 1, compatible with FTS_VENDOR_1_ID + * FTS_GET_VENDOR_ID_NUM >= 2, compatible with FTS_VENDOR_2_ID + * FTS_GET_VENDOR_ID_NUM == 3, compatible with FTS_VENDOR_3_ID + */ +#define FTS_VENDOR_1_ID 0x00 +#define FTS_VENDOR_2_ID 0x00 +#define FTS_VENDOR_3_ID 0x00 + +/* + * FW_APP.i file for auto upgrade, you must replace it with your own + * define your own fw_app, the sample one to be replaced is invalid + * NOTE: if FTS_GET_VENDOR_ID_NUM >= 1, it's the fw corresponding with FTS_VENDOR_1_ID + */ +#define FTS_UPGRADE_FW_APP "include/firmware/FT8716_app_sample.i" + +/* + * if FTS_GET_VENDOR_ID_NUM >= 2, fw corrsponding with FTS_VENDOR_2_ID + * define your own fw_app, the sample one is invalid + */ +#define FTS_UPGRADE_FW2_APP "include/firmware/FT8716_app_sample.i" + +/* + * if FTS_GET_VENDOR_ID_NUM == 3, fw corrsponding with FTS_VENDOR_3_ID + * define your own fw_app, the sample one is invalid + */ +#define FTS_UPGRADE_FW3_APP "include/firmware/FT8716_app_sample.i" + +/* + * upgrade stress test for debug + * enable it for upgrade debug if needed + * default: disable + */ +#define FTS_UPGRADE_STRESS_TEST 0 +/* stress test times, default: 1000 */ +#define FTS_UPGRADE_TEST_NUMBER 1000 + +/*********************************************************/ + +#endif /* _LINUX_FOCLATECH_CONFIG_H_ */ + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.c new file mode 100755 index 000000000000..2decdca1b1e6 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.c @@ -0,0 +1,1500 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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_core.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level */ +#endif + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_DRIVER_NAME "fts_ts" +#define INTERVAL_READ_REG 20 //interval time per read reg unit:ms +#define TIMEOUT_READ_REG 300 //timeout of read reg unit:ms +#if FTS_POWER_SOURCE_CUST_EN +#define FTS_VTG_MIN_UV 2600000 +#define FTS_VTG_MAX_UV 3300000 +#define FTS_I2C_VTG_MIN_UV 1800000 +#define FTS_I2C_VTG_MAX_UV 1800000 +#endif +#define FTS_READ_TOUCH_BUFFER_DIVIDED 0 +/***************************************************************************** +* Global variable or extern global variabls/functions +******************************************************************************/ +struct i2c_client *fts_i2c_client; +struct fts_ts_data *fts_wq_data; +struct input_dev *fts_input_dev; + +#if FTS_DEBUG_EN +int g_show_log = 1; +#else +int g_show_log = 0; +#endif + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) +char g_sz_debug[1024] = {0}; +#endif + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static void fts_release_all_finger(void); +static int fts_ts_suspend(struct device *dev); +static int fts_ts_resume(struct device *dev); + + +/***************************************************************************** +* Name: fts_wait_tp_to_valid +* Brief: Read chip id until TP FW become valid, need call when reset/power on/resume... +* 1. Read Chip ID per INTERVAL_READ_REG(20ms) +* 2. Timeout: TIMEOUT_READ_REG(300ms) +* Input: +* Output: +* Return: 0 - Get correct Device ID +*****************************************************************************/ +int fts_wait_tp_to_valid(struct i2c_client *client) +{ + int ret = 0; + int cnt = 0; + u8 reg_value = 0; + + do + { + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, ®_value); + if ((ret < 0) || (reg_value != chip_types.chip_idh)) + { + FTS_INFO("TP Not Ready, ReadData = 0x%x", reg_value); + } + else if (reg_value == chip_types.chip_idh) + { + FTS_INFO("TP Ready, Device ID = 0x%x", reg_value); + return 0; + } + cnt++; + msleep(INTERVAL_READ_REG); + } + while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG); + + /* error: not get correct reg data */ + return -1; +} + +/***************************************************************************** +* Name: fts_recover_state +* Brief: Need execute this function when reset +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_tp_state_recovery(struct i2c_client *client) +{ + /* wait tp stable */ + fts_wait_tp_to_valid(client); + /* recover TP charger state 0x8B */ + /* recover TP glove state 0xC0 */ + /* recover TP cover state 0xC1 */ + fts_ex_mode_recovery(client); + /* recover TP gesture state 0xD0 */ +#if FTS_GESTURE_EN + fts_gesture_recovery(client); +#endif +} + + +/***************************************************************************** +* Name: fts_reset_proc +* Brief: Execute reset operation +* Input: hdelayms - delay time unit:ms +* Output: +* Return: +*****************************************************************************/ +int fts_reset_proc(int hdelayms) +{ + gpio_direction_output(fts_wq_data->pdata->reset_gpio, 0); + msleep(20); + gpio_direction_output(fts_wq_data->pdata->reset_gpio, 1); + // gpio_direction_input(fts_wq_data->pdata->reset_gpio); + msleep(hdelayms); + + return 0; +} + +/***************************************************************************** +* Name: fts_irq_disable +* Brief: disable irq +* Input: +* sync: +* Output: +* Return: +*****************************************************************************/ +void fts_irq_disable(void) +{ + unsigned long irqflags; + spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags); + + if (!fts_wq_data->irq_disable) + { + disable_irq_nosync(fts_wq_data->client->irq); + fts_wq_data->irq_disable = 1; + } + + spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags); +} + +/***************************************************************************** +* Name: fts_irq_enable +* Brief: enable irq +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_irq_enable(void) +{ + unsigned long irqflags = 0; + spin_lock_irqsave(&fts_wq_data->irq_lock, irqflags); + + if (fts_wq_data->irq_disable) + { + enable_irq(fts_wq_data->client->irq); + fts_wq_data->irq_disable = 0; + } + + spin_unlock_irqrestore(&fts_wq_data->irq_lock, irqflags); +} + +/***************************************************************************** +* Name: fts_input_dev_init +* Brief: input dev init +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_input_dev_init( struct i2c_client *client, struct fts_ts_data *data, struct input_dev *input_dev, struct fts_ts_platform_data *pdata) +{ + int err, len; + + FTS_FUNC_ENTER(); + + /* Init and register Input device */ + input_dev->name = FTS_DRIVER_NAME; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + + input_set_drvdata(input_dev, data); + i2c_set_clientdata(client, data); + + __set_bit(EV_KEY, input_dev->evbit); + if (data->pdata->have_key) + { + FTS_DEBUG("set key capabilities"); + for (len = 0; len < data->pdata->key_number; len++) + { + input_set_capability(input_dev, EV_KEY, data->pdata->keys[len]); + } + } + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + +#if FTS_MT_PROTOCOL_B_EN + input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT); +#else + input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0f, 0, 0); +#endif + input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0); +#if FTS_REPORT_PRESSURE_EN + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0); +#endif + + err = input_register_device(input_dev); + if (err) + { + FTS_ERROR("Input device registration failed"); + goto free_inputdev; + } + + FTS_FUNC_EXIT(); + + return 0; + +free_inputdev: + input_free_device(input_dev); + FTS_FUNC_EXIT(); + return err; + +} + +/***************************************************************************** +* Power Control +*****************************************************************************/ +#if FTS_POWER_SOURCE_CUST_EN +static int fts_power_source_init(struct fts_ts_data *data) +{ + int rc; + + FTS_FUNC_ENTER(); + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) + { + rc = PTR_ERR(data->vdd); + FTS_ERROR("Regulator get failed vdd rc=%d", rc); + } + + if (regulator_count_voltages(data->vdd) > 0) + { + rc = regulator_set_voltage(data->vdd, FTS_VTG_MIN_UV, FTS_VTG_MAX_UV); + if (rc) + { + FTS_ERROR("Regulator set_vtg failed vdd rc=%d", rc); + goto reg_vdd_put; + } + } + + data->vcc_i2c = regulator_get(&data->client->dev, "vcc_i2c"); + if (IS_ERR(data->vcc_i2c)) + { + rc = PTR_ERR(data->vcc_i2c); + FTS_ERROR("Regulator get failed vcc_i2c rc=%d", rc); + goto reg_vdd_set_vtg; + } + + if (regulator_count_voltages(data->vcc_i2c) > 0) + { + rc = regulator_set_voltage(data->vcc_i2c, FTS_I2C_VTG_MIN_UV, FTS_I2C_VTG_MAX_UV); + if (rc) + { + FTS_ERROR("Regulator set_vtg failed vcc_i2c rc=%d", rc); + goto reg_vcc_i2c_put; + } + } + + FTS_FUNC_EXIT(); + return 0; + +reg_vcc_i2c_put: + regulator_put(data->vcc_i2c); +reg_vdd_set_vtg: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, FTS_VTG_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + FTS_FUNC_EXIT(); + return rc; +} + +static int fts_power_source_ctrl(struct fts_ts_data *data, int enable) +{ + int rc; + + FTS_FUNC_ENTER(); + if (enable) + { + rc = regulator_enable(data->vdd); + if (rc) + { + FTS_ERROR("Regulator vdd enable failed rc=%d", rc); + } + + rc = regulator_enable(data->vcc_i2c); + if (rc) + { + FTS_ERROR("Regulator vcc_i2c enable failed rc=%d", rc); + } + } + else + { + rc = regulator_disable(data->vdd); + if (rc) + { + FTS_ERROR("Regulator vdd disable failed rc=%d", rc); + } + rc = regulator_disable(data->vcc_i2c); + if (rc) + { + FTS_ERROR("Regulator vcc_i2c disable failed rc=%d", rc); + } + } + FTS_FUNC_EXIT(); + return 0; +} + +#endif + + +/***************************************************************************** +* Reprot related +*****************************************************************************/ +/***************************************************************************** +* Name: fts_release_all_finger +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_release_all_finger(void) +{ +#if FTS_MT_PROTOCOL_B_EN + unsigned int finger_count=0; +#endif + + mutex_lock(&fts_wq_data->report_mutex); +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; finger_count < fts_wq_data->pdata->max_touch_number; finger_count++) + { + input_mt_slot(fts_input_dev, finger_count); + input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER, false); + } +#else + input_mt_sync(fts_input_dev); +#endif + input_report_key(fts_input_dev, BTN_TOUCH, 0); + input_sync(fts_input_dev); + mutex_unlock(&fts_wq_data->report_mutex); +} + + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) +static void fts_show_touch_buffer(u8 *buf, int point_num) +{ + int len = point_num * FTS_ONE_TCH_LEN; + int count = 0; + int i; + + memset(g_sz_debug, 0, 1024); + if (len > (POINT_READ_BUF-3)) + { + len = POINT_READ_BUF-3; + } + else if (len == 0) + { + len += FTS_ONE_TCH_LEN; + } + count += sprintf(g_sz_debug, "%02X,%02X,%02X", buf[0], buf[1], buf[2]); + for (i = 0; i < len; i++) + { + count += sprintf(g_sz_debug+count, ",%02X", buf[i+3]); + } + FTS_DEBUG("buffer: %s", g_sz_debug); +} +#endif + +static int fts_input_dev_report_key_event(struct ts_event *event, struct fts_ts_data *data) +{ + int i; + + if (data->pdata->have_key) + { + if ( (1 == event->touch_point || 1 == event->point_num) && + (event->au16_y[0] == data->pdata->key_y_coord)) + { + + if (event->point_num == 0) + { + FTS_DEBUG("Keys All Up!"); + for (i = 0; i < data->pdata->key_number; i++) + { + input_report_key(data->input_dev, data->pdata->keys[i], 0); + } + } + else + { + for (i = 0; i < data->pdata->key_number; i++) + { + if (event->au16_x[0] > (data->pdata->key_x_coords[i] - FTS_KEY_WIDTH) && + event->au16_x[0] < (data->pdata->key_x_coords[i] + FTS_KEY_WIDTH)) + { + + if (event->au8_touch_event[i]== 0 || + event->au8_touch_event[i] == 2) + { + input_report_key(data->input_dev, data->pdata->keys[i], 1); + FTS_DEBUG("Key%d(%d, %d) DOWN!", i, event->au16_x[0], event->au16_y[0]); + } + else + { + input_report_key(data->input_dev, data->pdata->keys[i], 0); + FTS_DEBUG("Key%d(%d, %d) Up!", i, event->au16_x[0], event->au16_y[0]); + } + break; + } + } + } + input_sync(data->input_dev); + return 0; + } + } + + return -1; +} + +#if FTS_MT_PROTOCOL_B_EN +static int fts_input_dev_report_b(struct ts_event *event, struct fts_ts_data *data) +{ + int i = 0; + int uppoint = 0; + int touchs = 0; + for (i = 0; i < event->touch_point; i++) + { + if (event->au8_finger_id[i] >= data->pdata->max_touch_number) + { + break; + } + input_mt_slot(data->input_dev, event->au8_finger_id[i]); + + if (event->au8_touch_event[i] == FTS_TOUCH_DOWN || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) + { + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true); + +#if FTS_REPORT_PRESSURE_EN + if (event->pressure[i] <= 0) + { + FTS_ERROR("[B]Illegal pressure: %d", event->pressure[i]); + event->pressure[i] = 1; + } + input_report_abs(data->input_dev, ABS_MT_PRESSURE, event->pressure[i]); +#endif + + if (event->area[i] <= 0) + { + FTS_ERROR("[B]Illegal touch-major: %d", event->area[i]); + event->area[i] = 1; + } + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->area[i]); + + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]); + touchs |= BIT(event->au8_finger_id[i]); + data->touchs |= BIT(event->au8_finger_id[i]); + + FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", event->au8_finger_id[i], event->au16_x[i], + event->au16_y[i], event->pressure[i], event->area[i]); + } + else + { + uppoint++; + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); + data->touchs &= ~BIT(event->au8_finger_id[i]); + FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]); + } + } + + if (unlikely(data->touchs ^ touchs)) + { + for (i = 0; i < data->pdata->max_touch_number; i++) + { + if (BIT(i) & (data->touchs ^ touchs)) + { + FTS_DEBUG("[B]P%d UP!", i); + input_mt_slot(data->input_dev, i); + input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false); + } + } + } + + data->touchs = touchs; + if (event->touch_point == uppoint) + { + FTS_DEBUG("Points All Up!"); + input_report_key(data->input_dev, BTN_TOUCH, 0); + } + else + { + input_report_key(data->input_dev, BTN_TOUCH, event->touch_point > 0); + } + + input_sync(data->input_dev); + + return 0; + +} + +#else +static int fts_input_dev_report_a(struct ts_event *event,struct fts_ts_data *data) +{ + int i =0; + int uppoint = 0; + int touchs = 0; + + for (i = 0; i < event->touch_point; i++) + { + + if (event->au8_touch_event[i] == FTS_TOUCH_DOWN || event->au8_touch_event[i] == FTS_TOUCH_CONTACT) + { + input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->au8_finger_id[i]); +#if FTS_REPORT_PRESSURE_EN + if (event->pressure[i] <= 0) + { + FTS_ERROR("[B]Illegal pressure: %d", event->pressure[i]); + event->pressure[i] = 1; + } + input_report_abs(data->input_dev, ABS_MT_PRESSURE, event->pressure[i]); +#endif + + if (event->area[i] <= 0) + { + FTS_ERROR("[B]Illegal touch-major: %d", event->area[i]); + event->area[i] = 1; + } + input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->area[i]); + + input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->au16_x[i]); + input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]); + + input_mt_sync(data->input_dev); + + FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!", event->au8_finger_id[i], event->au16_x[i], + event->au16_y[i], event->pressure[i], event->area[i]); + } + else + { + uppoint++; + } + } + + data->touchs = touchs; + if (event->touch_point == uppoint) + { + FTS_DEBUG("Points All Up!"); + input_report_key(data->input_dev, BTN_TOUCH, 0); + input_mt_sync(data->input_dev); + } + else + { + input_report_key(data->input_dev, BTN_TOUCH, event->touch_point > 0); + } + + input_sync(data->input_dev); + + return 0; +} +#endif + +/***************************************************************************** +* Name: fts_read_touchdata +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_read_touchdata(struct fts_ts_data *data) +{ + u8 buf[POINT_READ_BUF] = { 0 }; + u8 pointid = FTS_MAX_ID; + int ret = -1; + int i; + struct ts_event * event = &(data->event); + +#if FTS_GESTURE_EN + { + u8 state; + if (data->suspended) + { + fts_i2c_read_reg(data->client, FTS_REG_GESTURE_EN, &state); + if (state ==1) + { + fts_gesture_readdata(data->client); + return 1; + } + } + } +#endif + +#if FTS_PSENSOR_EN + if ( (fts_sensor_read_data(data) != 0) && (data->suspended == 1) ) + { + return 1; + } +#endif + + +#if FTS_READ_TOUCH_BUFFER_DIVIDED + memset(buf, 0xFF, POINT_READ_BUF); + memset(event, 0, sizeof(struct ts_event)); + + buf[0] = 0x00; + ret = fts_i2c_read(data->client, buf, 1, buf, (3 + FTS_ONE_TCH_LEN)); + if (ret < 0) + { + FTS_ERROR("%s read touchdata failed.", __func__); + return ret; + } + event->touch_point = 0; + event->point_num=buf[FTS_TOUCH_POINT_NUM] & 0x0F; + if (event->point_num > data->pdata->max_touch_number) + event->point_num = data->pdata->max_touch_number; + + if (event->point_num > 1) + { + buf[9] = 0x09; + fts_i2c_read(data->client, buf+9, 1, buf+9, (event->point_num - 1) * FTS_ONE_TCH_LEN); + } +#else + ret = fts_i2c_read(data->client, buf, 1, buf, POINT_READ_BUF); + if (ret < 0) + { + FTS_ERROR("[B]Read touchdata failed, ret: %d", ret); + return ret; + } + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_queue_work(); +#endif + + memset(event, 0, sizeof(struct ts_event)); + event->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F; + if (event->point_num > data->pdata->max_touch_number) + event->point_num = data->pdata->max_touch_number; + event->touch_point = 0; +#endif + +#if (FTS_DEBUG_EN && (FTS_DEBUG_LEVEL == 2)) + fts_show_touch_buffer(buf, event->point_num); +#endif + + for (i = 0; i < data->pdata->max_touch_number; i++) + { + pointid = (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4; + if (pointid >= FTS_MAX_ID) + break; + else + event->touch_point++; + + event->au16_x[i] = + (s16) (buf[FTS_TOUCH_X_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F) << + 8 | (s16) buf[FTS_TOUCH_X_L_POS + FTS_ONE_TCH_LEN * i]; + event->au16_y[i] = + (s16) (buf[FTS_TOUCH_Y_H_POS + FTS_ONE_TCH_LEN * i] & 0x0F) << + 8 | (s16) buf[FTS_TOUCH_Y_L_POS + FTS_ONE_TCH_LEN * i]; + event->au8_touch_event[i] = + buf[FTS_TOUCH_EVENT_POS + FTS_ONE_TCH_LEN * i] >> 6; + event->au8_finger_id[i] = + (buf[FTS_TOUCH_ID_POS + FTS_ONE_TCH_LEN * i]) >> 4; + event->area[i] = + (buf[FTS_TOUCH_AREA_POS + FTS_ONE_TCH_LEN * i]) >> 4; + event->pressure[i] = + (s16) buf[FTS_TOUCH_PRE_POS + FTS_ONE_TCH_LEN * i]; + + if (0 == event->area[i]) + event->area[i] = 0x09; + + if (0 == event->pressure[i]) + event->pressure[i] = 0x3f; + + if ((event->au8_touch_event[i]==0 || event->au8_touch_event[i]==2)&&(event->point_num==0)) + { + FTS_DEBUG("abnormal touch data from fw"); + return -1; + } + } + if(event->touch_point == 0) + { + return -1; + } + return 0; +} + +/***************************************************************************** +* Name: fts_report_value +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_report_value(struct fts_ts_data *data) +{ + struct ts_event *event = &data->event; + + + FTS_DEBUG("point number: %d, touch point: %d", event->point_num, + event->touch_point); + + if (0 == fts_input_dev_report_key_event(event, data)) + { + return; + } + +#if FTS_MT_PROTOCOL_B_EN + fts_input_dev_report_b(event, data); +#else + fts_input_dev_report_a(event, data); +#endif + + + return; + +} + +/***************************************************************************** +* Name: fts_ts_interrupt +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static irqreturn_t fts_ts_interrupt(int irq, void *dev_id) +{ + struct fts_ts_data *fts_ts = dev_id; + int ret = -1; + + if (!fts_ts) + { + FTS_ERROR("[INTR]: Invalid fts_ts"); + return IRQ_HANDLED; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(1); +#endif + + ret = fts_read_touchdata(fts_wq_data); + + if (ret == 0) + { + mutex_lock(&fts_wq_data->report_mutex); + fts_report_value(fts_wq_data); + mutex_unlock(&fts_wq_data->report_mutex); + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_set_intr(0); +#endif + + return IRQ_HANDLED; +} + +/***************************************************************************** +* Name: fts_gpio_configure +* Brief: Configure IRQ&RESET GPIO +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_gpio_configure(struct fts_ts_data *data) +{ + int err = 0; + + FTS_FUNC_ENTER(); + /* request irq gpio */ + if (gpio_is_valid(data->pdata->irq_gpio)) + { + err = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio"); + if (err) + { + FTS_ERROR("[GPIO]irq gpio request failed"); + goto err_irq_gpio_req; + } + + err = gpio_direction_input(data->pdata->irq_gpio); + if (err) + { + FTS_ERROR("[GPIO]set_direction for irq gpio failed"); + goto err_irq_gpio_dir; + } + } + /* request reset gpio */ + if (gpio_is_valid(data->pdata->reset_gpio)) + { + err = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio"); + if (err) + { + FTS_ERROR("[GPIO]reset gpio request failed"); + goto err_irq_gpio_dir; + } + err = gpio_direction_output(data->pdata->reset_gpio, 1); + if (err) + { + FTS_ERROR("[GPIO]set_direction for reset gpio failed"); + goto err_reset_gpio_dir; + } + } else { + FTS_ERROR("[GPIO]reset is not valid"); + } + + FTS_FUNC_EXIT(); + return 0; + +err_reset_gpio_dir: + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); +err_irq_gpio_dir: + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); +err_irq_gpio_req: + FTS_FUNC_EXIT(); + return err; +} + + +/***************************************************************************** +* Name: fts_get_dt_coords +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_get_dt_coords(struct device *dev, char *name, + struct fts_ts_platform_data *pdata) +{ + u32 coords[FTS_COORDS_ARR_SIZE]; + struct property *prop; + struct device_node *np = dev->of_node; + int coords_size, rc; + + prop = of_find_property(np, name, NULL); + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + + coords_size = prop->length / sizeof(u32); + if (coords_size != FTS_COORDS_ARR_SIZE) + { + FTS_ERROR("invalid %s", name); + return -EINVAL; + } + + rc = of_property_read_u32_array(np, name, coords, coords_size); + if (rc && (rc != -EINVAL)) + { + FTS_ERROR("Unable to read %s", name); + return rc; + } + + if (!strcmp(name, "focaltech,display-coords")) + { + pdata->x_min = coords[0]; + pdata->y_min = coords[1]; + pdata->x_max = coords[2]; + pdata->y_max = coords[3]; + } + else + { + FTS_ERROR("unsupported property %s", name); + return -EINVAL; + } + + return 0; +} + +/***************************************************************************** +* Name: fts_parse_dt +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata) +{ + int rc; + struct device_node *np = dev->of_node; + u32 temp_val; + + FTS_FUNC_ENTER(); + + rc = fts_get_dt_coords(dev, "focaltech,display-coords", pdata); + if (rc) + FTS_ERROR("Unable to get display-coords"); + + /* key */ + pdata->have_key = of_property_read_bool(np, "focaltech,have-key"); + if (pdata->have_key) + { + rc = of_property_read_u32(np, "focaltech,key-number", &pdata->key_number); + if (rc) + { + FTS_ERROR("Key number undefined!"); + } + rc = of_property_read_u32_array(np, "focaltech,keys", + pdata->keys, pdata->key_number); + if (rc) + { + FTS_ERROR("Keys undefined!"); + } + rc = of_property_read_u32(np, "focaltech,key-y-coord", &pdata->key_y_coord); + if (rc) + { + FTS_ERROR("Key Y Coord undefined!"); + } + rc = of_property_read_u32_array(np, "focaltech,key-x-coords", + pdata->key_x_coords, pdata->key_number); + if (rc) + { + FTS_ERROR("Key X Coords undefined!"); + } + FTS_DEBUG("%d: (%d, %d, %d), [%d, %d, %d][%d]", + pdata->key_number, pdata->keys[0], pdata->keys[1], pdata->keys[2], + pdata->key_x_coords[0], pdata->key_x_coords[1], pdata->key_x_coords[2], + pdata->key_y_coord); + } + + /* reset, irq gpio info */ + pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &pdata->reset_gpio_flags); + if (pdata->reset_gpio < 0) + { + FTS_ERROR("Unable to get reset_gpio"); + } + + pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, &pdata->irq_gpio_flags); + if (pdata->irq_gpio < 0) + { + FTS_ERROR("Unable to get irq_gpio"); + } + + rc = of_property_read_u32(np, "max-touch-number", &temp_val); + if (!rc) + { + pdata->max_touch_number = temp_val; + FTS_DEBUG("max_touch_number=%d", pdata->max_touch_number); + } + else + { + FTS_DEBUG("Unable to get max-touch-number"); + pdata->max_touch_number = FTS_MAX_POINTS; + } + + rc = of_property_read_u32(np, "x_max", &temp_val); + if (!rc) + { + pdata->x_max = temp_val; + FTS_DEBUG("x_max=%d", pdata->x_max); + } + + rc = of_property_read_u32(np, "y_max", &temp_val); + if (!rc) + { + pdata->x_max = temp_val; + FTS_DEBUG("y_max=%d", pdata->x_max); + } + + + FTS_FUNC_EXIT(); + return 0; +} + +#if defined(CONFIG_FB) +/***************************************************************************** +* Name: fb_notifier_callback +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct fts_ts_data *fts_data = + container_of(self, struct fts_ts_data, fb_notif); + + if (evdata && evdata->data && event == FB_EVENT_BLANK && + fts_data && fts_data->client) + { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) + fts_ts_resume(&fts_data->client->dev); + else if (*blank == FB_BLANK_POWERDOWN) + fts_ts_suspend(&fts_data->client->dev); + } + + return 0; +} +#elif defined(CONFIG_HAS_EARLYSUSPEND) +/***************************************************************************** +* Name: fts_ts_early_suspend +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_ts_early_suspend(struct early_suspend *handler) +{ + struct fts_ts_data *data = container_of(handler, + struct fts_ts_data, + early_suspend); + + fts_ts_suspend(&data->client->dev); +} + +/***************************************************************************** +* Name: fts_ts_late_resume +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_ts_late_resume(struct early_suspend *handler) +{ + struct fts_ts_data *data = container_of(handler, + struct fts_ts_data, + early_suspend); + + fts_ts_resume(&data->client->dev); +} +#endif + +/***************************************************************************** +* Name: fts_ts_probe +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct fts_ts_platform_data *pdata; + struct fts_ts_data *data; + struct input_dev *input_dev; + int err; + + FTS_FUNC_ENTER(); + /* 1. Get Platform data */ + if (client->dev.of_node) + { + pdata = devm_kzalloc(&client->dev, + sizeof(struct fts_ts_platform_data), + GFP_KERNEL); + if (!pdata) + { + FTS_ERROR("[MEMORY]Failed to allocate memory"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + err = fts_parse_dt(&client->dev, pdata); + if (err) + { + FTS_ERROR("[DTS]DT parsing failed"); + } + } + else + { + pdata = client->dev.platform_data; + } + + if (!pdata) + { + FTS_ERROR("Invalid pdata"); + FTS_FUNC_EXIT(); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + FTS_ERROR("I2C not supported"); + FTS_FUNC_EXIT(); + return -ENODEV; + } + + data = devm_kzalloc(&client->dev, sizeof(struct fts_ts_data), GFP_KERNEL); + if (!data) + { + FTS_ERROR("[MEMORY]Failed to allocate memory"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + + input_dev = input_allocate_device(); + if (!input_dev) + { + FTS_ERROR("[INPUT]Failed to allocate input device"); + FTS_FUNC_EXIT(); + return -ENOMEM; + } + + + + data->input_dev = input_dev; + data->client = client; + data->pdata = pdata; + + fts_wq_data = data; + fts_i2c_client = client; + fts_input_dev = input_dev; + + spin_lock_init(&fts_wq_data->irq_lock); + mutex_init(&fts_wq_data->report_mutex); + + fts_input_dev_init(client, data, input_dev, pdata); + + fts_ctpm_get_upgrade_array(); + +#if FTS_POWER_SOURCE_CUST_EN + fts_power_source_init(data); + fts_power_source_ctrl(data, 1); +#endif + + err = fts_gpio_configure(data); + if (err < 0) + { + FTS_ERROR("[GPIO]Failed to configure the gpios"); + goto free_gpio; + } + + fts_reset_proc(200); + fts_wait_tp_to_valid(client); + + client->irq = gpio_to_irq(data->pdata->irq_gpio); + err = request_threaded_irq(client->irq, NULL, fts_ts_interrupt, + pdata->irq_gpio_flags | IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + client->dev.driver->name, data); + if (err) + { + FTS_ERROR("Request irq failed!"); + goto free_gpio; + } + + fts_irq_disable(); + +#if FTS_PSENSOR_EN + if ( fts_sensor_init(data) != 0) + { + FTS_ERROR("fts_sensor_init failed!"); + FTS_FUNC_EXIT(); + return 0; + } +#endif + +#if FTS_APK_NODE_EN + fts_create_apk_debug_channel(client); +#endif + +#if FTS_SYSFS_NODE_EN + fts_create_sysfs(client); +#endif + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_init(); +#endif + + fts_ex_mode_init(client); + +#if FTS_GESTURE_EN + fts_gesture_init(input_dev, client); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_init(); +#endif + + fts_irq_enable(); + +#if FTS_AUTO_UPGRADE_EN + fts_ctpm_upgrade_init(); +#endif + +#if defined(CONFIG_FB) + data->fb_notif.notifier_call = fb_notifier_callback; + err = fb_register_client(&data->fb_notif); + if (err) + FTS_ERROR("[FB]Unable to register fb_notifier: %d", err); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL; + data->early_suspend.suspend = fts_ts_early_suspend; + data->early_suspend.resume = fts_ts_late_resume; + register_early_suspend(&data->early_suspend); +#endif + + FTS_FUNC_EXIT(); + return 0; + +free_gpio: + if (gpio_is_valid(pdata->reset_gpio)) + gpio_free(pdata->reset_gpio); + if (gpio_is_valid(pdata->irq_gpio)) + gpio_free(pdata->irq_gpio); + return err; + +} + +/***************************************************************************** +* Name: fts_ts_remove +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_remove(struct i2c_client *client) +{ + struct fts_ts_data *data = i2c_get_clientdata(client); + + FTS_FUNC_ENTER(); + cancel_work_sync(&data->touch_event_work); + +#if FTS_PSENSOR_EN + fts_sensor_remove(data); +#endif + +#if FTS_POINT_REPORT_CHECK_EN + fts_point_report_check_exit(); +#endif + +#if FTS_APK_NODE_EN + fts_release_apk_debug_channel(); +#endif + +#if FTS_SYSFS_NODE_EN + fts_remove_sysfs(client); +#endif + + fts_ex_mode_exit(client); + +#if FTS_AUTO_UPGRADE_EN + cancel_work_sync(&fw_update_work); +#endif + +#if defined(CONFIG_FB) + if (fb_unregister_client(&data->fb_notif)) + FTS_ERROR("Error occurred while unregistering fb_notifier."); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&data->early_suspend); +#endif + free_irq(client->irq, data); + + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); + + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); + + input_unregister_device(data->input_dev); + +#if FTS_ESDCHECK_EN + fts_esdcheck_exit(); +#endif + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_ts_suspend +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_suspend(struct device *dev) +{ + struct fts_ts_data *data = dev_get_drvdata(dev); + int retval = 0; + + FTS_FUNC_ENTER(); + if (data->suspended) + { + FTS_INFO("Already in suspend state"); + FTS_FUNC_EXIT(); + return -1; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_suspend(); +#endif + +#if FTS_GESTURE_EN + retval = fts_gesture_suspend(data->client); + if (retval == 0) + { + /* Enter into gesture mode(suspend) */ + retval = enable_irq_wake(fts_wq_data->client->irq); + if (retval) + FTS_ERROR("%s: set_irq_wake failed", __func__); + data->suspended = true; + FTS_FUNC_EXIT(); + return 0; + } +#endif + +#if FTS_PSENSOR_EN + if ( fts_sensor_suspend(data) != 0 ) + { + enable_irq_wake(data->client->irq); + data->suspended = true; + return 0; + } +#endif + + fts_irq_disable(); + + /* TP enter sleep mode */ + retval = fts_i2c_write_reg(data->client, FTS_REG_POWER_MODE, FTS_REG_POWER_MODE_SLEEP_VALUE); + if (retval < 0) + { + FTS_ERROR("Set TP to sleep mode fail, ret=%d!", retval); + } + data->suspended = true; + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_ts_resume +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_ts_resume(struct device *dev) +{ + struct fts_ts_data *data = dev_get_drvdata(dev); + + FTS_FUNC_ENTER(); + if (!data->suspended) + { + FTS_DEBUG("Already in awake state"); + FTS_FUNC_EXIT(); + return -1; + } + + fts_release_all_finger(); + +#if (!FTS_CHIP_IDC) + fts_reset_proc(200); +#endif + + fts_tp_state_recovery(data->client); + +#if FTS_ESDCHECK_EN + fts_esdcheck_resume(); +#endif + +#if FTS_GESTURE_EN + if (fts_gesture_resume(data->client) == 0) + { + int err; + err = disable_irq_wake(data->client->irq); + if (err) + FTS_ERROR("%s: disable_irq_wake failed",__func__); + data->suspended = false; + FTS_FUNC_EXIT(); + return 0; + } +#endif + +#if FTS_PSENSOR_EN + if ( fts_sensor_resume(data) != 0 ) + { + disable_irq_wake(data->client->irq); + data->suspended = false; + FTS_FUNC_EXIT(); + return 0; + } +#endif + + data->suspended = false; + + fts_irq_enable(); + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* I2C Driver +*****************************************************************************/ +static const struct i2c_device_id fts_ts_id[] = +{ + {FTS_DRIVER_NAME, 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, fts_ts_id); + +static struct of_device_id fts_match_table[] = +{ + { .compatible = "focaltech,fts", }, + { }, +}; + +static struct i2c_driver fts_ts_driver = +{ + .probe = fts_ts_probe, + .remove = fts_ts_remove, + .driver = { + .name = FTS_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = fts_match_table, + }, + .id_table = fts_ts_id, +}; + +/***************************************************************************** +* Name: fts_ts_init +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int __init fts_ts_init(void) +{ + int ret = 0; + + FTS_FUNC_ENTER(); + ret = i2c_add_driver(&fts_ts_driver); + if ( ret != 0 ) + { + FTS_ERROR("Focaltech touch screen driver init failed!"); + } + FTS_FUNC_EXIT(); + return ret; +} + +/***************************************************************************** +* Name: fts_ts_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void __exit fts_ts_exit(void) +{ + i2c_del_driver(&fts_ts_driver); +} + +module_init(fts_ts_init); +module_exit(fts_ts_exit); + +MODULE_AUTHOR("FocalTech Driver Team"); +MODULE_DESCRIPTION("FocalTech Touchscreen Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.h b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.h new file mode 100755 index 000000000000..72c5637f3d1b --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_core.h @@ -0,0 +1,194 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +/***************************************************************************** +* +* File Name: focaltech_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "focaltech_common.h" +#include "focaltech_flash.h" +#if FTS_PSENSOR_EN +#include +#endif +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define LEN_FLASH_ECC_MAX 0xFFFE + +#define FTS_WORKQUEUE_NAME "fts_wq" + +#define FTS_MAX_POINTS 10 +#define FTS_KEY_WIDTH 50 +#define FTS_ONE_TCH_LEN 6 +#define POINT_READ_BUF (3 + FTS_ONE_TCH_LEN * FTS_MAX_POINTS) + +#define FTS_MAX_ID 0x0F +#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_TOUCH_DOWN 0 +#define FTS_TOUCH_UP 1 +#define FTS_TOUCH_CONTACT 2 + +#define FTS_SYSFS_ECHO_ON(buf) ((strncmp(buf, "1", 1) == 0) || \ + (strncmp(buf, "on", 2) == 0)) +#define FTS_SYSFS_ECHO_OFF(buf) ((strncmp(buf, "0", 1) == 0) || \ + (strncmp(buf, "off", 3) == 0)) + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + + +struct fts_ts_platform_data +{ + u32 irq_gpio; + u32 irq_gpio_flags; + u32 reset_gpio; + u32 reset_gpio_flags; + bool have_key; + u32 key_number; + u32 keys[4]; + u32 key_y_coord; + u32 key_x_coords[4]; + u32 x_max; + u32 y_max; + u32 x_min; + u32 y_min; + u32 max_touch_number; +}; + +struct ts_event +{ + u16 au16_x[FTS_MAX_POINTS]; /*x coordinate */ + u16 au16_y[FTS_MAX_POINTS]; /*y coordinate */ + u16 pressure[FTS_MAX_POINTS]; + u8 au8_touch_event[FTS_MAX_POINTS]; /* touch event: 0 -- down; 1-- up; 2 -- contact */ + u8 au8_finger_id[FTS_MAX_POINTS]; /*touch ID */ + u8 area[FTS_MAX_POINTS]; + u8 touch_point; + u8 point_num; +}; + +struct fts_ts_data +{ + struct i2c_client *client; + struct input_dev *input_dev; + struct ts_event event; + const struct fts_ts_platform_data *pdata; +#if FTS_PSENSOR_EN + struct fts_psensor_platform_data *psensor_pdata; +#endif + struct work_struct touch_event_work; + struct workqueue_struct *ts_workqueue; + struct regulator *vdd; + struct regulator *vcc_i2c; + spinlock_t irq_lock; + struct mutex report_mutex; + u16 addr; + bool suspended; + u8 fw_ver[3]; + u8 fw_vendor_id; + int touchs; + int irq_disable; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif +}; + + +#if FTS_PSENSOR_EN +struct fts_psensor_platform_data +{ + struct input_dev *input_psensor_dev; + struct sensors_classdev ps_cdev; + int tp_psensor_opened; + char tp_psensor_data; /* 0 near, 1 far */ + struct fts_ts_data *data; +}; + +int fts_sensor_init(struct fts_ts_data *data); +int fts_sensor_read_data(struct fts_ts_data *data); +int fts_sensor_suspend(struct fts_ts_data *data); +int fts_sensor_resume(struct fts_ts_data *data); +int fts_sensor_remove(struct fts_ts_data *data); +#endif + +/***************************************************************************** +* Static variables +*****************************************************************************/ +extern struct i2c_client *fts_i2c_client; +extern struct fts_ts_data *fts_wq_data; +extern struct input_dev *fts_input_dev; + +#endif /* __LINUX_FOCALTECH_CORE_H__ */ diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_esdcheck.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_esdcheck.c new file mode 100755 index 000000000000..a012c75c21df --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_esdcheck.c @@ -0,0 +1,491 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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: luoguojin +* +* 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 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +struct fts_esdcheck_st +{ + u8 active : 1; /* 1- esd check active, need check esd 0- no esd check */ + u8 suspend : 1; + u8 proc_debug : 1; /* apk or adb is accessing I2C */ + u8 intr : 1; /* 1- Interrupt trigger */ + u8 unused : 4; + 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 i2c_nack_cnt; + u32 i2c_dataerror_cnt; +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct delayed_work fts_esdcheck_work; +static struct workqueue_struct *fts_esdcheck_workqueue = NULL; +static struct fts_esdcheck_st fts_esdcheck_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ +#if LCD_ESD_PATCH +/***************************************************************************** +* Name: lcd_esdcheck +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +int lcd_need_reset; +static int tp_need_recovery; /* LCD reset cause Tp reset */ +int idc_esdcheck_lcderror(void) +{ + u8 val; + int ret; + + FTS_DEBUG("[ESD]Check LCD ESD"); + if ( (tp_need_recovery == 1) && (lcd_need_reset == 0) ) + { + tp_need_recovery = 0; + /* LCD reset, need recover TP state */ + fts_tp_state_recovery(fts_i2c_client); + } + + ret = fts_i2c_read_reg(fts_i2c_client, FTS_REG_ESD_SATURATE, &val); + if ( ret < 0) + { + FTS_ERROR("[ESD]: Read ESD_SATURATE(0xED) failed 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, Execute LCD reset!"); + lcd_need_reset = 1; + tp_need_recovery = 1; + } + + return 0; +} +#endif + +/***************************************************************************** +* Name: fts_esdcheck_tp_reset +* Brief: esd check algorithm +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_esdcheck_tp_reset( void ) +{ + FTS_FUNC_ENTER(); + + fts_esdcheck_data.flow_work_hold_cnt = 0; + fts_esdcheck_data.hardware_reset_cnt++; + + fts_reset_proc(200); + fts_tp_state_recovery(fts_i2c_client); + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: get_chip_id +* Brief: Read Chip Id 3 times +* Input: +* Output: +* Return: 1 - Read Chip Id 3 times failed +* 0 - Read Chip Id pass +*****************************************************************************/ +static bool get_chip_id( void ) +{ + int err = 0; + int i = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + + for (i = 0; i < 3; i++) + { + reg_addr = FTS_REG_CHIP_ID; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, ®_value, 1); + + if ( err < 0 ) + { + FTS_ERROR("[ESD]: Read Reg 0xA3 failed ret = %d!!", err); + fts_esdcheck_data.i2c_nack_cnt++; + } + else + { + if ( (reg_value == chip_types.chip_idh) || (reg_value == 0xEF) ) /* Upgrade sometimes can't detect */ + { + break; + } + else + { + fts_esdcheck_data.i2c_dataerror_cnt++; + } + } + } + + /* if can't get correct data in 3 times, then need hardware reset */ + if (i >= 3) + { + FTS_ERROR("[ESD]: Read Chip id 3 times failed, need execute TP reset!!"); + return 1; + } + + return 0; +} + +/***************************************************************************** +* Name: get_flow_cnt +* Brief: Read flow cnt(0x91) +* Input: +* Output: +* Return: 1 - Reg 0x91(flow cnt) abnormal: hold a value for 5 times +* 0 - Reg 0x91(flow cnt) normal +*****************************************************************************/ +static bool get_flow_cnt( void ) +{ + int err = 0; + u8 reg_value = 0; + u8 reg_addr = 0; + + reg_addr = FTS_REG_FLOW_WORK_CNT; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, ®_value, 1); + if (err < 0) + { + FTS_ERROR("[ESD]: Read Reg 0x91 failed ret = %d!!", err); + fts_esdcheck_data.i2c_nack_cnt++; + } + else + { + if ( 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; + } + + /* if read flow work cnt 5 times and the value are all the same, then need hardware_reset */ + if (fts_esdcheck_data.flow_work_hold_cnt >= 5) + { + FTS_DEBUG("[ESD]: Flow Work Cnt(reg0x91) keep a value for 5 times, need execute TP reset!!"); + return 1; + } + + return 0; +} + +/***************************************************************************** +* Name: esdcheck_algorithm +* Brief: esd check algorithm +* Input: +* Output: +* Return: +*****************************************************************************/ +static int esdcheck_algorithm(void) +{ + int err = 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_INFO("[ESD]: In interrupt state, not check esd, return immediately!!"); + return 0; + } + + /* 2. check power state, if suspend, no need check esd */ + if (fts_esdcheck_data.suspend == 1) + { + FTS_INFO("[ESD]: In suspend, not check esd, return immediately!!"); + /* 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 + */ + fts_esdcheck_data.active = 0; + 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("[ESD]: In apk or adb command mode, not check esd, return immediately!!"); + return 0; + } + + /* 4. In factory mode, can't check esd */ + reg_addr = FTS_REG_WORKMODE; + err = fts_i2c_read(fts_i2c_client, ®_addr, 1, ®_value, 1); + if ( err < 0 ) + { + fts_esdcheck_data.i2c_nack_cnt++; + } + else if ( (reg_value & 0x70) == FTS_REG_WORKMODE_FACTORY_VALUE) + { + FTS_INFO("[ESD]: In factory mode, not check esd, return immediately!!"); + return 0; + } + + /* 5. IDC esd check lcd default:close */ +#if LCD_ESD_PATCH + idc_esdcheck_lcderror(); +#endif + + /* 6. Get Chip ID */ + hardware_reset = get_chip_id(); + + /* 7. get Flow work cnt: 0x91 If no change for 5 times, then ESD and reset */ + if (!hardware_reset) + { + hardware_reset = get_flow_cnt(); + } + + /* 8. If need hardware reset, then handle it here */ + if ( hardware_reset == 1) + { + fts_esdcheck_tp_reset(); + } + + FTS_INFO("[ESD]: NoACK=%d, Error Data=%d, Hardware Reset=%d\n", fts_esdcheck_data.i2c_nack_cnt, fts_esdcheck_data.i2c_dataerror_cnt, fts_esdcheck_data.hardware_reset_cnt); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_func +* Brief: fts_esdcheck_func +* Input: +* Output: +* Return: +*****************************************************************************/ +static void esdcheck_func(struct work_struct *work) +{ + FTS_FUNC_ENTER(); + + esdcheck_algorithm(); + + if ( fts_esdcheck_data.suspend == 0 ) + { + queue_delayed_work(fts_esdcheck_workqueue, &fts_esdcheck_work, msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } + + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_esdcheck_set_intr +* Brief: interrupt flag (main used in interrupt tp report) +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_set_intr(bool intr) +{ + /* interrupt don't add debug message */ + fts_esdcheck_data.intr = intr; + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_get_status(void) +* Brief: get current status +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_get_status(void) +{ + /* interrupt don't add debug message */ + return fts_esdcheck_data.active; +} + +/***************************************************************************** +* 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) +{ + FTS_FUNC_ENTER(); + if (enable == 1) + { + if (fts_esdcheck_data.active == 0) + { + FTS_INFO("[ESD]: ESD check start!!"); + fts_esdcheck_data.active = 1; + queue_delayed_work(fts_esdcheck_workqueue, &fts_esdcheck_work, msecs_to_jiffies(ESDCHECK_WAIT_TIME)); + } + } + else + { + if (fts_esdcheck_data.active == 1) + { + FTS_INFO("[ESD]: ESD check stop!!"); + fts_esdcheck_data.active = 0; + cancel_delayed_work_sync(&fts_esdcheck_work); + } + } + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_suspend +* Brief: Run when tp enter into suspend +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_suspend(void) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(DISABLE); + fts_esdcheck_data.suspend = 1; + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_resume +* Brief: Run when tp resume +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_resume( void ) +{ + FTS_FUNC_ENTER(); + fts_esdcheck_switch(ENABLE); + fts_esdcheck_data.suspend = 0; + FTS_FUNC_EXIT(); + return 0; +} + + +/***************************************************************************** +* Name: fts_esdcheck_init +* Brief: Init and create a queue work to check esd +* Input: +* Output: +* Return: < 0: Fail to create esd check queue +*****************************************************************************/ +int fts_esdcheck_init(void) +{ + FTS_FUNC_ENTER(); + + INIT_DELAYED_WORK(&fts_esdcheck_work, esdcheck_func); + fts_esdcheck_workqueue = create_workqueue("fts_esdcheck_wq"); + if (fts_esdcheck_workqueue == NULL) + { + FTS_INFO("[ESD]: Failed to create esd work queue!!"); + } + + memset((u8 *)&fts_esdcheck_data, 0, sizeof(struct fts_esdcheck_st)); + + fts_esdcheck_switch(ENABLE); + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_esdcheck_exit +* Brief: When FTS TP driver is removed, then call this function to destory work queue +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_esdcheck_exit(void) +{ + FTS_FUNC_ENTER(); + + destroy_workqueue(fts_esdcheck_workqueue); + + FTS_FUNC_EXIT(); + return 0; +} +#endif /* FTS_ESDCHECK_EN */ + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_fun.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_fun.c new file mode 100755 index 000000000000..3c4e9cf5dc6b --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_fun.c @@ -0,0 +1,1351 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: Focaltech_ex_fun.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 +*****************************************************************************/ +/*create apk debug channel*/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 +#define PROC_SET_TEST_FLAG 8 +#define PROC_SET_SLAVE_ADDR 10 +#define PROC_HW_RESET 11 +#define PROC_NAME "ftxxxx-debug" +#define WRITE_BUF_SIZE 512 +#define READ_BUF_SIZE 512 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static unsigned char proc_operate_mode = PROC_UPGRADE; +static struct proc_dir_entry *fts_proc_entry; +static struct +{ + int op; // 0: read, 1: write + int reg; // register + int value; // read: return value, write: op return + int result; // 0: success, otherwise: fail +} g_rwreg_result; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if FTS_ESDCHECK_EN +static void esd_process(u8 *writebuf, int buflen, bool flag) +{ + if (flag) + { + if ( (writebuf[1] == 0xFC) && (writebuf[2] == 0x55) && (buflen == 0x03) ) + { + /* Upgrade command */ + FTS_DEBUG("[ESD]: Upgrade command(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(DISABLE); + } + else if ( (writebuf[1] == 0x00) && (writebuf[2] == 0x40) && (buflen == 0x03) ) + { + /* factory mode bit 4 5 6 */ + FTS_DEBUG("[ESD]: Entry factory mode(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(DISABLE); + } + else if ( (writebuf[1] == 0x00) && (writebuf[2] == 0x00) && (buflen == 0x03) ) + { + /* normal mode bit 4 5 6 */ + FTS_DEBUG("[ESD]: Exit factory mode(%x %x %x)!!", writebuf[0], writebuf[1], writebuf[2]); + fts_esdcheck_switch(ENABLE); + } + else + { + fts_esdcheck_proc_busy(1); + } + } + else + { + if ( (writebuf[1] == 0x07) && (buflen == 0x02) ) + { + FTS_DEBUG("[ESD]: Upgrade finish-trigger reset(07)(%x %x)!!", writebuf[0], writebuf[1]); + fts_esdcheck_switch(ENABLE); + } + else + { + fts_esdcheck_proc_busy(0); + } + } +} +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +/*interface of write proc*/ +/************************************************************************ +* Name: fts_debug_write +* Brief:interface of write proc +* Input: file point, data buf, data len, no use +* Output: no +* Return: data len +***********************************************************************/ +static ssize_t fts_debug_write(struct file *filp, const char __user *buff, size_t count, loff_t *ppos) +{ + unsigned char writebuf[WRITE_BUF_SIZE]; + int buflen = count; + int writelen = 0; + int ret = 0; + char tmp[25]; + + if (copy_from_user(&writebuf, buff, buflen)) + { + FTS_DEBUG("[APK]: copy from user error!!"); + return -EFAULT; + } +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 1); +#endif + proc_operate_mode = writebuf[0]; + switch (proc_operate_mode) + { + case PROC_UPGRADE: + { + char upgrade_file_path[FILE_NAME_LENGTH]; + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + sprintf(upgrade_file_path, "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + FTS_DEBUG("%s\n", upgrade_file_path); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_bin_file) + ret = fts_updatefun_curr.upgrade_with_app_bin_file(fts_i2c_client, upgrade_file_path); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + if (ret < 0) + { + FTS_ERROR("[APK]: upgrade failed!!"); + } + } + break; + + case PROC_SET_TEST_FLAG: + FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x!!", writebuf[1]); +#if FTS_ESDCHECK_EN + if (writebuf[1] == 0) + { + fts_esdcheck_switch(DISABLE); + } + else + { + fts_esdcheck_switch(ENABLE); + } +#endif + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!"); + } + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!"); + } + break; + case PROC_SET_SLAVE_ADDR: + + ret = fts_i2c_client->addr; + FTS_DEBUG("Original i2c addr 0x%x ", ret<<1 ); + if (writebuf[1] != fts_i2c_client->addr) + { + fts_i2c_client->addr = writebuf[1]; + FTS_DEBUG("Change i2c addr 0x%x to 0x%x", ret<<1, writebuf[1]<<1); + + } + break; + + case PROC_HW_RESET: + + sprintf(tmp, "%s", writebuf + 1); + tmp[buflen - 1] = '\0'; + if (strncmp(tmp,"focal_driver",12)==0) + { + FTS_DEBUG("Begin HW Reset"); + fts_reset_proc(1); + } + + break; + + case PROC_AUTOCLB: + FTS_DEBUG("[APK]: autoclb!!"); + fts_ctpm_auto_clb(fts_i2c_client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = count - 1; + if (writelen>0) + { + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!"); + } + } + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 0); +#endif + + if (ret < 0) + { + return ret; + } + else + { + return count; + } +} + +/* interface of read proc */ +/************************************************************************ +* Name: fts_debug_read +* Brief:interface of read proc +* Input: point to the data, no use, no use, read len, no use, no use +* Output: page point to data +* Return: read char number +***********************************************************************/ +static ssize_t fts_debug_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos) +{ + int ret = 0; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + unsigned char buf[READ_BUF_SIZE]; + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + switch (proc_operate_mode) + { + case PROC_UPGRADE: + // after calling fts_debug_write to upgrade + regaddr = FTS_REG_FW_VER; + ret = fts_i2c_read_reg(fts_i2c_client, regaddr, ®value); + if (ret < 0) + num_read_chars = sprintf(buf, "%s", "get fw version failed.\n"); + else + num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) + { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) + { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + if (copy_to_user(buff, buf, num_read_chars)) + { + FTS_ERROR("[APK]: copy to user error!!"); + return -EFAULT; + } + + return num_read_chars; +} +static const struct file_operations fts_proc_fops = +{ + .owner = THIS_MODULE, + .read = fts_debug_read, + .write = fts_debug_write, +}; +#else +/* interface of write proc */ +/************************************************************************ +* Name: fts_debug_write +* Brief:interface of write proc +* Input: file point, data buf, data len, no use +* Output: no +* Return: data len +***********************************************************************/ +static int fts_debug_write(struct file *filp, + const char __user *buff, unsigned long len, void *data) +{ + unsigned char writebuf[WRITE_BUF_SIZE]; + int buflen = len; + int writelen = 0; + int ret = 0; + char tmp[25]; + + if (copy_from_user(&writebuf, buff, buflen)) + { + FTS_ERROR("[APK]: copy from user error!!"); + return -EFAULT; + } +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 1); +#endif + proc_operate_mode = writebuf[0]; + switch (proc_operate_mode) + { + + case PROC_UPGRADE: + { + char upgrade_file_path[FILE_NAME_LENGTH]; + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + sprintf(upgrade_file_path, "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + FTS_DEBUG("%s\n", upgrade_file_path); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_bin_file) + ret = fts_updatefun_curr.upgrade_with_app_bin_file(fts_i2c_client, upgrade_file_path); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + if (ret < 0) + { + FTS_ERROR("[APK]: upgrade failed!!"); + } + } + break; + case PROC_SET_TEST_FLAG: + FTS_DEBUG("[APK]: PROC_SET_TEST_FLAG = %x!!", writebuf[1]); +#if FTS_ESDCHECK_EN + if (writebuf[1] == 0) + { + fts_esdcheck_switch(DISABLE); + } + else + { + fts_esdcheck_switch(ENABLE); + } +#endif + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!n"); + } + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!"); + } + break; + case PROC_SET_SLAVE_ADDR: + + ret = fts_i2c_client->addr; + FTS_DEBUG("Original i2c addr 0x%x ", ret<<1 ); + if (writebuf[1] != fts_i2c_client->addr) + { + fts_i2c_client->addr = writebuf[1]; + FTS_DEBUG("Change i2c addr 0x%x to 0x%x", ret<<1, writebuf[1]<<1); + + } + break; + + case PROC_HW_RESET: + + sprintf(tmp, "%s", writebuf + 1); + tmp[buflen - 1] = '\0'; + if (strncmp(tmp,"focal_driver",12)==0) + { + FTS_DEBUG("Begin HW Reset"); + fts_reset_proc(1); + } + + break; + + case PROC_AUTOCLB: + FTS_DEBUG("[APK]: autoclb!!"); + fts_ctpm_auto_clb(fts_i2c_client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = len - 1; + if (writelen>0) + { + ret = fts_i2c_write(fts_i2c_client, writebuf + 1, writelen); + if (ret < 0) + { + FTS_ERROR("[APK]: write iic error!!"); + } + } + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + esd_process(writebuf, buflen, 0); +#endif + + if (ret < 0) + { + return ret; + } + else + { + return len; + } +} + +/* interface of read proc */ +/************************************************************************ +* Name: fts_debug_read +* Brief:interface of read proc +* Input: point to the data, no use, no use, read len, no use, no use +* Output: page point to data +* Return: read char number +***********************************************************************/ +static int fts_debug_read( char *page, char **start, + off_t off, int count, int *eof, void *data ) +{ + int ret = 0; + unsigned char buf[READ_BUF_SIZE]; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + switch (proc_operate_mode) + { + case PROC_UPGRADE: + // after calling fts_debug_write to upgrade + regaddr = FTS_REG_FW_VER; + ret = fts_i2c_read_reg(fts_i2c_client, regaddr, ®value); + if (ret < 0) + num_read_chars = sprintf(buf, "%s", "get fw version failed.\n"); + else + num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) + { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = fts_i2c_read(fts_i2c_client, NULL, 0, buf, readlen); + if (ret < 0) + { +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + FTS_ERROR("[APK]: read iic error!!"); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + + memcpy(page, buf, num_read_chars); + return num_read_chars; +} +#endif +/************************************************************************ +* Name: fts_create_apk_debug_channel +* Brief: create apk debug channel +* Input: i2c info +* Output: no +* Return: success =0 +***********************************************************************/ +int fts_create_apk_debug_channel(struct i2c_client * client) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + fts_proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops); +#else + fts_proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); +#endif + if (NULL == fts_proc_entry) + { + FTS_ERROR("Couldn't create proc entry!"); + return -ENOMEM; + } + else + { + FTS_INFO("Create proc entry success!"); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) + fts_proc_entry->write_proc = fts_debug_write; + fts_proc_entry->read_proc = fts_debug_read; +#endif + } + return 0; +} +/************************************************************************ +* Name: fts_release_apk_debug_channel +* Brief: release apk debug channel +* Input: no +* Output: no +* Return: no +***********************************************************************/ +void fts_release_apk_debug_channel(void) +{ + + if (fts_proc_entry) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + proc_remove(fts_proc_entry); +#else + remove_proc_entry(PROC_NAME, NULL); +#endif +} + +/* + * fts_hw_reset interface + */ +static ssize_t fts_hw_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return -EPERM; +} +static ssize_t fts_hw_reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + + fts_reset_proc(200); + + count = snprintf(buf, PAGE_SIZE, "hw reset executed\n"); + + return count; +} + +/* + * fts_irq interface + */ +static ssize_t fts_irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + if (FTS_SYSFS_ECHO_ON(buf)) + { + FTS_INFO("[EX-FUN]enable irq"); + fts_irq_enable(); + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + FTS_INFO("[EX-FUN]disable irq"); + fts_irq_disable(); + } + return count; +} + +static ssize_t fts_irq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return -EPERM; +} + +/************************************************************************ +* Name: fts_tpfwver_show +* Brief: show tp fw vwersion +* Input: device, device attribute, char buf +* Output: no +* Return: char number +***********************************************************************/ +static ssize_t fts_tpfwver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t num_read_chars = 0; + u8 fwver = 0; + + mutex_lock(&fts_input_dev->mutex); + +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + if (fts_i2c_read_reg(fts_i2c_client, FTS_REG_FW_VER, &fwver) < 0) + { + num_read_chars = snprintf(buf, PAGE_SIZE,"I2c transfer error!\n"); + } +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + if (fwver == 255) + num_read_chars = snprintf(buf, PAGE_SIZE,"get tp fw version fail!\n"); + else + { + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver); + } + + mutex_unlock(&fts_input_dev->mutex); + + return num_read_chars; +} +/************************************************************************ +* Name: fts_tpfwver_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_tpfwver_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +static int fts_is_hex_char(const char ch) +{ + int result = 0; + if (ch >= '0' && ch <= '9') + { + result = 1;//(int)(ch - '0'); + } + else if (ch >= 'a' && ch <= 'f') + { + result = 1;//(int)(ch - 'a') + 10; + } + else if (ch >= 'A' && ch <= 'F') + { + result = 1;//(int)(ch - 'A') + 10; + } + else + { + result = 0; + } + + return result; +} + +static int fts_hex_char_to_int(const char ch) +{ + int result = 0; + if (ch >= '0' && ch <= '9') + { + result = (int)(ch - '0'); + } + else if (ch >= 'a' && ch <= 'f') + { + result = (int)(ch - 'a') + 10; + } + else if (ch >= 'A' && ch <= 'F') + { + result = (int)(ch - 'A') + 10; + } + else + { + result = -1; + } + + return result; +} + +static int fts_hex_to_str(char *hex, int iHexLen, char *ch, int *iChLen) +{ + int high=0; + int low=0; + int tmp = 0; + int i = 0; + int iCharLen = 0; + if (hex == NULL || ch == NULL) + { + return -1; + } + + FTS_DEBUG("iHexLen: %d in function:%s!!\n\n", iHexLen, __func__); + + if (iHexLen %2 == 1) + { + return -2; + } + + for (i=0; imutex); + + if (!g_rwreg_result.op) + { + if (g_rwreg_result.result == 0) + { + count = sprintf(buf, "Read %02X: %02X\n", g_rwreg_result.reg, g_rwreg_result.value); + } + else + { + count = sprintf(buf, "Read %02X failed, ret: %d\n",g_rwreg_result.reg, g_rwreg_result.result); + } + } + else + { + if (g_rwreg_result.result == 0) + { + count = sprintf(buf, "Write %02X, %02X success\n",g_rwreg_result.reg, g_rwreg_result.value); + } + else + { + count = sprintf(buf, "Write %02X failed, ret: %d\n",g_rwreg_result.reg, g_rwreg_result.result); + } + } + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_tprwreg_store +* Brief: read/write register +* Input: device, device attribute, char buf, char count +* Output: print register value +* Return: char count +***********************************************************************/ +static ssize_t fts_tprwreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + ssize_t num_read_chars = 0; + int retval; + long unsigned int wmreg=0; + u8 regaddr=0xff,regvalue=0xff; + u8 valbuf[5]= {0}; + + memset(valbuf, 0, sizeof(valbuf)); + mutex_lock(&fts_input_dev->mutex); + num_read_chars = count - 1; + if (num_read_chars != 2) + { + if (num_read_chars != 4) + { + FTS_ERROR("please input 2 or 4 character"); + goto error_return; + } + } + memcpy(valbuf, buf, num_read_chars); + retval = kstrtoul(valbuf, 16, &wmreg); + fts_str_to_bytes((char*)buf, num_read_chars, valbuf, &retval); + + if (1==retval) + { + regaddr = valbuf[0]; + retval = 0; + } + else if (2==retval) + { + regaddr = valbuf[0]; + regvalue = valbuf[1]; + retval = 0; + } + else + retval =-1; + + if (0 != retval) + { + FTS_ERROR("%s() - ERROR: Could not convert the given input to a number. The given input was: \"%s\"", __FUNCTION__, buf); + goto error_return; + } +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + if (2 == num_read_chars) + { + g_rwreg_result.op = 0; + g_rwreg_result.reg = regaddr; + /*read register*/ + regaddr = wmreg; + g_rwreg_result.result = fts_i2c_read_reg(client, regaddr, ®value); + if (g_rwreg_result.result < 0) + { + FTS_ERROR("Could not read the register(0x%02x)", regaddr); + } + else + { + FTS_INFO("the register(0x%02x) is 0x%02x", regaddr, regvalue); + g_rwreg_result.value = regvalue; + g_rwreg_result.result = 0; + } + } + else + { + regaddr = wmreg>>8; + regvalue = wmreg; + + g_rwreg_result.op = 1; + g_rwreg_result.reg = regaddr; + g_rwreg_result.value = regvalue; + g_rwreg_result.result = fts_i2c_write_reg(client, regaddr, regvalue); + if (g_rwreg_result.result < 0) + { + FTS_ERROR("Could not write the register(0x%02x)", regaddr); + + } + else + { + FTS_INFO("Write 0x%02x into register(0x%02x) successful", regvalue, regaddr); + g_rwreg_result.result = 0; + } + } +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif +error_return: + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_fwupdate_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_fwupdate_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_fwupdate_store +* Brief: upgrade from *.i +* Input: device, device attribute, char buf, char count +* Output: no +* Return: char count +***********************************************************************/ +static ssize_t fts_fwupdate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&fts_input_dev->mutex); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + + if (fts_updatefun_curr.upgrade_with_app_i_file) + fts_updatefun_curr.upgrade_with_app_i_file(client); +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN + if (fts_updatefun_curr.upgrade_with_lcd_cfg_i_file) + fts_updatefun_curr.upgrade_with_lcd_cfg_i_file(client); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_fwupgradeapp_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_fwupgradeapp_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_fwupgradeapp_store +* Brief: upgrade from app.bin +* Input: device, device attribute, char buf, char count +* Output: no +* Return: char count +***********************************************************************/ +static ssize_t fts_fwupgradeapp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + char fwname[FILE_NAME_LENGTH]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + memset(fwname, 0, sizeof(fwname)); + sprintf(fwname, "%s", buf); + fwname[count-1] = '\0'; + + mutex_lock(&fts_input_dev->mutex); + fts_irq_disable(); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + if (fts_updatefun_curr.upgrade_with_app_bin_file) + fts_updatefun_curr.upgrade_with_app_bin_file(client, fwname); +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_driverversion_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_driverversion_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = sprintf(buf, FTS_DRIVER_VERSION "\n"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_driverversion_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_driverversion_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +#if FTS_ESDCHECK_EN +/************************************************************************ +* Name: fts_esdcheck_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_esdcheck_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + mutex_lock(&fts_input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) + { + FTS_DEBUG("enable esdcheck"); + fts_esdcheck_switch(ENABLE); + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + FTS_DEBUG("disable esdcheck"); + fts_esdcheck_switch(DISABLE); + } + mutex_unlock(&fts_input_dev->mutex); + + return -EPERM; +} + +/************************************************************************ +* Name: fts_esdcheck_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_esdcheck_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = sprintf(buf, "Esd check: %s\n", fts_esdcheck_get_status() ? "On" : "Off"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +#endif +/************************************************************************ +* Name: fts_module_config_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_module_config_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count = 0; + + mutex_lock(&fts_input_dev->mutex); + + count += sprintf(buf, "FTS_CHIP_TYPE: \t\t\t%04X\n", FTS_CHIP_TYPE); + count += sprintf(buf+count, "FTS_DEBUG_EN: \t\t\t%s\n", FTS_DEBUG_EN ? "ON" : "OFF"); +#if defined(FTS_MT_PROTOCOL_B_EN) + count += sprintf(buf+count, "TS_MT_PROTOCOL_B_EN: \t\t%s\n", FTS_MT_PROTOCOL_B_EN ? "ON" : "OFF"); +#endif + count += sprintf(buf+count, "FTS_GESTURE_EN: \t\t%s\n", FTS_GESTURE_EN ? "ON" : "OFF"); + count += sprintf(buf+count, "FTS_ESDCHECK_EN: \t\t%s\n", FTS_ESDCHECK_EN ? "ON" : "OFF"); +#if defined(FTS_PSENSOR_EN) + count += sprintf(buf+count, "FTS_PSENSOR_EN: \t\t%s\n", FTS_PSENSOR_EN ? "ON" : "OFF"); +#endif + count += sprintf(buf+count, "FTS_GLOVE_EN: \t\t\t%s\n", FTS_GLOVE_EN ? "ON" : "OFF"); + count += sprintf(buf+count, "FTS_COVER_EN: \t\t%s\n", FTS_COVER_EN ? "ON" : "OFF"); + count += sprintf(buf+count, "FTS_CHARGER_EN: \t\t\t%s\n", FTS_CHARGER_EN ? "ON" : "OFF"); + + count += sprintf(buf+count, "FTS_REPORT_PRESSURE_EN: \t\t%s\n", FTS_REPORT_PRESSURE_EN ? "ON" : "OFF"); + + count += sprintf(buf+count, "FTS_APK_NODE_EN: \t\t%s\n", FTS_APK_NODE_EN ? "ON" : "OFF"); + count += sprintf(buf+count, "FTS_POWER_SOURCE_CUST_EN: \t%s\n", FTS_POWER_SOURCE_CUST_EN ? "ON" : "OFF"); + count += sprintf(buf+count, "FTS_AUTO_UPGRADE_EN: \t\t%s\n", FTS_AUTO_UPGRADE_EN ? "ON" : "OFF"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_module_config_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_module_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_show_log_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_show_log_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + + mutex_lock(&fts_input_dev->mutex); + + count = sprintf(buf, "Log: %s\n", g_show_log ? "On" : "Off"); + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} +/************************************************************************ +* Name: fts_show_log_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_show_log_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + + mutex_lock(&fts_input_dev->mutex); + if (FTS_SYSFS_ECHO_ON(buf)) + { + FTS_DEBUG("enable show log info/error"); + g_show_log = 1; + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + FTS_DEBUG("disable show log info/error"); + g_show_log = 0; + } + mutex_unlock(&fts_input_dev->mutex); + return count; +} +/************************************************************************ +* Name: fts_dumpreg_store +* Brief: no +* Input: device, device attribute, char buf, char count +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_dumpreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/************************************************************************ +* Name: fts_dumpreg_show +* Brief: no +* Input: device, device attribute, char buf +* Output: no +* Return: EPERM +***********************************************************************/ +static ssize_t fts_dumpreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + char tmp[256]; + int count = 0; + u8 regvalue = 0; + struct i2c_client *client; + + mutex_lock(&fts_input_dev->mutex); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(1); +#endif + client = container_of(dev, struct i2c_client, dev); + fts_i2c_read_reg(client, FTS_REG_POWER_MODE, ®value); //power mode 0:active 1:monitor 3:sleep + count += sprintf(tmp + count, "Power Mode:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_FW_VER, ®value); //FWver + count += sprintf(tmp + count, "FW Ver:0x%02x\n",regvalue); + + fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, ®value); //Vendor ID + count += sprintf(tmp + count, "Vendor ID:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_LCD_BUSY_NUM, ®value); //LCD Busy number + count += sprintf(tmp + count, "LCD Busy Number:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, ®value); // 1 Gesture mode,0 Normal mode + count += sprintf(tmp + count, "Gesture Mode:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_CHARGER_MODE_EN, ®value); // 3 charge in + count += sprintf(tmp + count, "charge stat:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_INT_CNT, ®value); //Interrupt counter + count += sprintf(tmp + count, "INT count:0x%02x\n", regvalue); + + fts_i2c_read_reg(client, FTS_REG_FLOW_WORK_CNT, ®value); //Flow work counter + count += sprintf(tmp + count, "ESD count:0x%02x\n", regvalue); +#if FTS_ESDCHECK_EN + fts_esdcheck_proc_busy(0); +#endif + memcpy(buf, tmp, count); + mutex_unlock(&fts_input_dev->mutex); + return count; +} + +/****************************************/ +/* sysfs */ +/* get the fw version +* example:cat fw_version +*/ +static DEVICE_ATTR(fts_fw_version, S_IRUGO|S_IWUSR, fts_tpfwver_show, fts_tpfwver_store); + +/* upgrade from *.i +* example: echo 1 > fw_update +*/ +static DEVICE_ATTR(fts_fw_update, S_IRUGO|S_IWUSR, fts_fwupdate_show, fts_fwupdate_store); +/* read and write register +* read example: echo 88 > rw_reg ---read register 0x88 +* write example:echo 8807 > rw_reg ---write 0x07 into register 0x88 +* +* note:the number of input must be 2 or 4.if it not enough,please fill in the 0. +*/ +static DEVICE_ATTR(fts_rw_reg, S_IRUGO|S_IWUSR, fts_tprwreg_show, fts_tprwreg_store); +/* upgrade from app.bin +* example:echo "*_app.bin" > upgrade_app +*/ +static DEVICE_ATTR(fts_upgrade_app, S_IRUGO|S_IWUSR, fts_fwupgradeapp_show, fts_fwupgradeapp_store); +static DEVICE_ATTR(fts_driver_version, S_IRUGO|S_IWUSR, fts_driverversion_show, fts_driverversion_store); +static DEVICE_ATTR(fts_dump_reg, S_IRUGO|S_IWUSR, fts_dumpreg_show, fts_dumpreg_store); +static DEVICE_ATTR(fts_show_log, S_IRUGO|S_IWUSR, fts_show_log_show, fts_show_log_store); +static DEVICE_ATTR(fts_module_config, S_IRUGO|S_IWUSR, fts_module_config_show, fts_module_config_store); +static DEVICE_ATTR(fts_hw_reset, S_IRUGO|S_IWUSR, fts_hw_reset_show, fts_hw_reset_store); +static DEVICE_ATTR(fts_irq, S_IRUGO|S_IWUSR, fts_irq_show, fts_irq_store); + +#if FTS_ESDCHECK_EN +static DEVICE_ATTR(fts_esd_check, S_IRUGO|S_IWUSR, fts_esdcheck_show, fts_esdcheck_store); +#endif + +/* add your attr in here*/ +static struct attribute *fts_attributes[] = +{ + &dev_attr_fts_fw_version.attr, + &dev_attr_fts_fw_update.attr, + &dev_attr_fts_rw_reg.attr, + &dev_attr_fts_dump_reg.attr, + &dev_attr_fts_upgrade_app.attr, + &dev_attr_fts_driver_version.attr, + &dev_attr_fts_show_log.attr, + &dev_attr_fts_module_config.attr, + &dev_attr_fts_hw_reset.attr, + &dev_attr_fts_irq.attr, +#if FTS_ESDCHECK_EN + &dev_attr_fts_esd_check.attr, +#endif + NULL +}; + +static struct attribute_group fts_attribute_group = +{ + .attrs = fts_attributes +}; + +/************************************************************************ +* Name: fts_create_sysfs +* Brief: create sysfs for debug +* Input: i2c info +* Output: no +* Return: success =0 +***********************************************************************/ +int fts_create_sysfs(struct i2c_client * client) +{ + int err; + err = sysfs_create_group(&client->dev.kobj, &fts_attribute_group); + if (0 != err) + { + FTS_ERROR("[EX]: sysfs_create_group() failed!!"); + sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); + return -EIO; + } + else + { + FTS_INFO("[EX]: sysfs_create_group() succeeded!!"); + } + return err; +} +/************************************************************************ +* Name: fts_remove_sysfs +* Brief: remove sys +* Input: i2c info +* Output: no +* Return: no +***********************************************************************/ +int fts_remove_sysfs(struct i2c_client * client) +{ + sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); + return 0; +} diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_mode.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_mode.c new file mode 100755 index 000000000000..8d461728c2ae --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_ex_mode.c @@ -0,0 +1,376 @@ +/* + * + * FocalTech ftxxxx TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_ex_mode.c +* +* Author: Liu WeiGuang +* +* 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 +*****************************************************************************/ +struct fts_mode_flag +{ + int fts_glove_mode_flag; + int fts_cover_mode_flag; + int fts_charger_mode_flag; +}; + +struct fts_mode_flag g_fts_mode_flag; + +/***************************************************************************** +* 4.Static variables +*****************************************************************************/ + +/***************************************************************************** +* 5.Global variable or extern global variabls/functions +*****************************************************************************/ +int fts_enter_glove_mode(struct i2c_client *client, int mode ); +int fts_glove_init(struct i2c_client *client); +int fts_glove_exit(struct i2c_client *client); + +int fts_enter_cover_mode(struct i2c_client *client, int mode ); +int fts_cover_init(struct i2c_client *client); +int fts_cover_exit(struct i2c_client *client); + +int fts_enter_charger_mode(struct i2c_client *client, int mode ); +int fts_charger_init(struct i2c_client *client); +int fts_charger_exit(struct i2c_client *client); + +/***************************************************************************** +* 6.Static function prototypes +*******************************************************************************/ + +#if FTS_GLOVE_EN +static ssize_t fts_touch_glove_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Glove: %s\n", g_fts_mode_flag.fts_glove_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_glove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) + { + if (!g_fts_mode_flag.fts_glove_mode_flag) + { + FTS_INFO("[Mode]enter glove mode"); + ret = fts_enter_glove_mode(fts_i2c_client,true); + if (ret >= 0) + { + g_fts_mode_flag.fts_glove_mode_flag = true; + } + } + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + if (g_fts_mode_flag.fts_glove_mode_flag) + { + FTS_INFO("[Mode]exit glove mode"); + ret = fts_enter_glove_mode(fts_i2c_client,false); + if (ret >= 0) + { + g_fts_mode_flag.fts_glove_mode_flag = false; + } + } + } + FTS_INFO("[Mode]glove mode status: %d", g_fts_mode_flag.fts_glove_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_glove_mode +* Brief: change glove mode +* Input: glove mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_glove_mode( struct i2c_client *client, int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + buf_addr[0] = FTS_REG_GLOVE_MODE_EN; //glove control + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg( client, buf_addr[0], buf_value[0]); + if (ret<0) + { + FTS_ERROR("[Mode]fts_enter_glove_mode write value fail"); + } + + return ret ; + +} + +/* read and write glove mode +* read example: cat fts_touch_glove_mode---read glove mode +* write example:echo 01 > fts_touch_glove_mode ---write glove mode to 01 +* +*/ +static DEVICE_ATTR (fts_glove_mode, S_IRUGO|S_IWUSR, fts_touch_glove_show, fts_touch_glove_store); + +#endif + +#if FTS_COVER_EN +static ssize_t fts_touch_cover_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Cover: %s\n", g_fts_mode_flag.fts_cover_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_cover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) + { + if (!g_fts_mode_flag.fts_cover_mode_flag) + { + FTS_INFO("[Mode]enter cover mode"); + ret = fts_enter_cover_mode(fts_i2c_client,true); + if (ret >= 0) + { + g_fts_mode_flag.fts_cover_mode_flag = true; + } + } + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + if (g_fts_mode_flag.fts_cover_mode_flag) + { + FTS_INFO("[Mode]exit cover mode"); + ret = fts_enter_cover_mode(fts_i2c_client,false); + if (ret >= 0) + { + g_fts_mode_flag.fts_cover_mode_flag = false; + } + } + } + FTS_INFO("[Mode]cover mode status: %d",g_fts_mode_flag.fts_cover_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_cover_mode +* Brief: change cover mode +* Input: cover mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_cover_mode( struct i2c_client *client,int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + buf_addr[0] = FTS_REG_COVER_MODE_EN; //cover control + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg( client,buf_addr[0], buf_value[0]); + if (ret<0) + { + FTS_ERROR("[Mode] fts_enter_cover_mode write value fail \n"); + } + + return ret ; + +} + +/* read and write cover mode +* read example: cat fts_touch_cover_mode---read cover mode +* write example:echo 01 > fts_touch_cover_mode ---write cover mode to 01 +* +*/ +static DEVICE_ATTR (fts_cover_mode, S_IRUGO|S_IWUSR, fts_touch_cover_show, fts_touch_cover_store); + +#endif + +#if FTS_CHARGER_EN +static ssize_t fts_touch_charger_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "Charger: %s\n", g_fts_mode_flag.fts_charger_mode_flag ? "On" : "Off"); +} + +static ssize_t fts_touch_charger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + + if (FTS_SYSFS_ECHO_ON(buf)) + { + if (!g_fts_mode_flag.fts_charger_mode_flag) + { + FTS_INFO("[Mode]enter charger mode"); + ret = fts_enter_charger_mode(fts_i2c_client,true); + if (ret >= 0) + { + g_fts_mode_flag.fts_charger_mode_flag = true; + } + } + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + if (g_fts_mode_flag.fts_charger_mode_flag) + { + FTS_INFO("[Mode]exit charger mode"); + ret = fts_enter_charger_mode(fts_i2c_client,false); + if (ret >= 0) + { + g_fts_mode_flag.fts_charger_mode_flag = false; + } + } + } + FTS_INFO("[Mode]charger mode status: %d", g_fts_mode_flag.fts_charger_mode_flag); + return count; +} + +/************************************************************************ +* Name: fts_enter_charger_mode +* Brief: change charger mode +* Input: charger mode +* Output: no +* Return: success >=0, otherwise failed +***********************************************************************/ +int fts_enter_charger_mode(struct i2c_client *client, int mode) +{ + int ret = 0; + static u8 buf_addr[2] = { 0 }; + static u8 buf_value[2] = { 0 }; + buf_addr[0] = FTS_REG_CHARGER_MODE_EN; //charger control + + if (mode) + buf_value[0] = 0x01; + else + buf_value[0] = 0x00; + + ret = fts_i2c_write_reg( client, buf_addr[0], buf_value[0]); + if (ret<0) + { + FTS_DEBUG("[Mode]fts_enter_charger_mode write value fail"); + } + + return ret ; + +} + +/* read and write charger mode +* read example: cat fts_touch_charger_mode---read charger mode +* write example:echo 01 > fts_touch_charger_mode ---write charger mode to 01 +* +*/ +static DEVICE_ATTR (fts_charger_mode, S_IRUGO|S_IWUSR, fts_touch_charger_show, fts_touch_charger_store); + +#endif + +static struct attribute *fts_touch_mode_attrs[] = +{ +#if FTS_GLOVE_EN + &dev_attr_fts_glove_mode.attr, +#endif + +#if FTS_COVER_EN + &dev_attr_fts_cover_mode.attr, +#endif + +#if FTS_CHARGER_EN + &dev_attr_fts_charger_mode.attr, +#endif + + NULL, +}; + +static struct attribute_group fts_touch_mode_group = +{ + .attrs = fts_touch_mode_attrs, +}; + +int fts_ex_mode_init(struct i2c_client *client) +{ + int err=0; + + g_fts_mode_flag.fts_glove_mode_flag = false; + g_fts_mode_flag.fts_cover_mode_flag = false; + g_fts_mode_flag.fts_charger_mode_flag = false; + + err = sysfs_create_group(&client->dev.kobj, &fts_touch_mode_group); + if (0 != err) + { + FTS_ERROR("[Mode]create sysfs failed."); + sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group); + return -EIO; + } + else + { + FTS_DEBUG("[Mode]create sysfs succeeded"); + } + + return err; + +} + +int fts_ex_mode_exit(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &fts_touch_mode_group); + return 0; +} + +int fts_ex_mode_recovery(struct i2c_client *client) +{ + int ret = 0; +#if FTS_GLOVE_EN + if (g_fts_mode_flag.fts_glove_mode_flag) + ret = fts_enter_glove_mode(client, true); +#endif + +#if FTS_COVER_EN + if (g_fts_mode_flag.fts_cover_mode_flag) + ret = fts_enter_cover_mode(client, true); +#endif + +#if FTS_CHARGER_EN + if (g_fts_mode_flag.fts_charger_mode_flag) + ret = fts_enter_charger_mode(client, true); +#endif + + return ret; +} + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.c new file mode 100755 index 000000000000..7b61f943eb9c --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.c @@ -0,0 +1,860 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_flash.c +* +* Author: fupeipei +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#include "focaltech_flash.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +struct ft_chip_t chip_types; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +/* Upgrade FW/PRAMBOOT/LCD CFG */ + u8 CTPM_FW[] = +{ +//#include FTS_UPGRADE_FW_APP +"include/firmware/FT8716_app_sample.i" + +}; + +#if (FTS_GET_VENDOR_ID_NUM >= 2) +u8 CTPM_FW2[] = +{ +#include FTS_UPGRADE_FW2_APP +}; +#endif + +#if (FTS_GET_VENDOR_ID_NUM >= 3) +u8 CTPM_FW3[] = +{ +#include FTS_UPGRADE_FW3_APP +}; +#endif + +u8 aucFW_PRAM_BOOT[] = +{ +#ifdef FTS_UPGRADE_PRAMBOOT +#include FTS_UPGRADE_PRAMBOOT +#endif +}; + +struct fts_upgrade_fun fts_updatefun_curr; +struct workqueue_struct *touch_wq; +struct work_struct fw_update_work; +u8 *g_fw_file; +int g_fw_len; +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/************************************************************************ +* Name: fts_ctpm_upgrade_delay +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +void fts_ctpm_upgrade_delay(u32 i) +{ + do + { + i--; + } + while (i>0); +} + +/************************************************************************ +* Name: fts_ctpm_i2c_hid2std +* Brief: HID to I2C +* Input: i2c info +* Output: no +* Return: fail =0 +***********************************************************************/ +int fts_ctpm_i2c_hid2std(struct i2c_client *client) +{ +#if (FTS_CHIP_IDC) + return 0; +#else + u8 buf[5] = {0}; + int bRet = 0; + + buf[0] = 0xeb; + buf[1] = 0xaa; + buf[2] = 0x09; + bRet =fts_i2c_write(client, buf, 3); + msleep(10); + buf[0] = buf[1] = buf[2] = 0; + fts_i2c_read(client, buf, 0, buf, 3); + + if ((0xeb == buf[0]) && (0xaa == buf[1]) && (0x08 == buf[2])) + { + FTS_DEBUG("hidi2c change to stdi2c successful!!"); + bRet = 1; + } + else + { + FTS_ERROR("hidi2c change to stdi2c error!!"); + bRet = 0; + } + + return bRet; +#endif +} + +/************************************************************************ +* Name: fts_get_chip_types +* Brief: get correct chip information +* Input: +* Output: +* Return: +***********************************************************************/ +void fts_get_chip_types(void) +{ + struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING; + int ic_type = 0; + + if (sizeof(ctype) != sizeof(struct ft_chip_t)) /* only one array */ + ic_type = IC_SERIALS - 1; + + chip_types = ctype[ic_type]; + + FTS_INFO("CHIP TYPE ID = 0x%02x%02x", chip_types.chip_idh, chip_types.chip_idl); +} + +/************************************************************************ +* Name: fts_ctpm_get_upgrade_array +* Brief: decide which ic +* Input: no +* Output: get ic info in fts_updateinfo_curr +* Return: no +***********************************************************************/ +void fts_ctpm_get_upgrade_array(void) +{ + + FTS_FUNC_ENTER(); + + fts_get_chip_types(); + + fts_ctpm_i2c_hid2std(fts_i2c_client); + + /* Get functin pointer */ + memcpy(&fts_updatefun_curr, &fts_updatefun, sizeof(struct fts_upgrade_fun)); + + FTS_FUNC_EXIT(); +} + +/************************************************************************ +* Name: fts_ctpm_rom_or_pram_reset +* Brief: RST CMD(07), reset to romboot(maybe->bootloader) +* Input: +* Output: +* Return: +***********************************************************************/ +void fts_ctpm_rom_or_pram_reset(struct i2c_client *client) +{ + u8 rst_cmd = FTS_REG_RESET_FW; + + FTS_INFO("[UPGRADE]******Reset to romboot/bootloader******"); + fts_i2c_write(client, &rst_cmd, 1); + /* The delay can't be changed */ + msleep(300); +} + +/************************************************************************ +* Name: fts_ctpm_auto_clb +* Brief: auto calibration +* Input: i2c info +* Output: no +* Return: 0 +***********************************************************************/ +int fts_ctpm_auto_clb(struct i2c_client *client) +{ +#if FTS_AUTO_CLB_EN + u8 uc_temp = 0x00; + u8 i = 0; + + /*start auto CLB */ + msleep(200); + + fts_i2c_write_reg(client, 0, FTS_REG_WORKMODE_FACTORY_VALUE); + /*make sure already enter factory mode */ + msleep(100); + /*write command to start calibration */ + fts_i2c_write_reg(client, 2, 0x4); + msleep(300); + if ((chip_types.chip_idh==0x11) ||(chip_types.chip_idh==0x12) ||(chip_types.chip_idh==0x13) ||(chip_types.chip_idh==0x14)) //5x36,5x36i + { + for (i=0; i<100; i++) + { + fts_i2c_read_reg(client, 0x02, &uc_temp); + if (0x02 == uc_temp || + 0xFF == uc_temp) + { + break; + } + msleep(20); + } + } + else + { + for (i=0; i<100; i++) + { + fts_i2c_read_reg(client, 0, &uc_temp); + if (0x0 == ((uc_temp&0x70)>>4)) + { + break; + } + msleep(20); + } + } + fts_i2c_write_reg(client, 0, 0x40); + msleep(200); + fts_i2c_write_reg(client, 2, 0x5); + msleep(300); + fts_i2c_write_reg(client, 0, FTS_REG_WORKMODE_WORK_VALUE); + msleep(300); +#endif + + return 0; +} + +/************************************************************************ +* Name: fts_GetFirmwareSize +* Brief: get file size +* Input: file name +* Output: no +* Return: file size +***********************************************************************/ +int fts_GetFirmwareSize(char *firmware_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[FILE_NAME_LENGTH]; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FTXXXX_INI_FILEPATH_CONFIG, firmware_name); + if (NULL == pfile) + { + pfile = filp_open(filepath, O_RDONLY, 0); + } + if (IS_ERR(pfile)) + { + FTS_ERROR("error occured while opening file %s", filepath); + return -EIO; + } + inode = pfile->f_path.dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + +/************************************************************************ +* Name: fts_ReadFirmware +* Brief: read firmware buf for .bin file. +* Input: file name, data buf +* Output: data buf +* Return: 0 +***********************************************************************/ +int fts_ReadFirmware(char *firmware_name,u8 *firmware_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[FILE_NAME_LENGTH]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "%s%s", FTXXXX_INI_FILEPATH_CONFIG, firmware_name); + if (NULL == pfile) + { + pfile = filp_open(filepath, O_RDONLY, 0); + } + if (IS_ERR(pfile)) + { + FTS_ERROR("[UPGRADE] Error occured while opening file %s.\n", filepath); + return -EIO; + } + inode = pfile->f_path.dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, firmware_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + return 0; +} + +/************************************************************************ +* Name: fts_getsize +* Brief: Get different file's size +* Input: +* Output: +* Return: file's size +***********************************************************************/ +u32 fts_getsize(u8 fw_type) +{ + int fw_len = 0; + + if (fw_type == FW_SIZE) + fw_len = sizeof(CTPM_FW); +#if (FTS_GET_VENDOR_ID_NUM >= 2) + else if (fw_type == FW2_SIZE) + fw_len = sizeof(CTPM_FW2); +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + else if (fw_type == FW3_SIZE) + fw_len = sizeof(CTPM_FW3); +#endif +#if FTS_CHIP_IDC + else if (fw_type == PRAMBOOT_SIZE) + fw_len = sizeof(aucFW_PRAM_BOOT); +#endif + + return fw_len; +} + +/************************************************************************ +* Name: fts_ctpm_get_pram_or_rom_id +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +enum FW_STATUS fts_ctpm_get_pram_or_rom_id(struct i2c_client *client) +{ + u8 buf[4]; + u8 reg_val[2] = {0}; + enum FW_STATUS inRomBoot = FTS_RUN_IN_ERROR; + + fts_ctpm_i2c_hid2std(client); + + /*Enter upgrade mode*/ + /*send 0x55 in time windows*/ + buf[0] = FTS_UPGRADE_55; + buf[1] = FTS_UPGRADE_AA; + fts_i2c_write(client, buf, 2); + + msleep(20); + + buf[0] = 0x90; + buf[1] = buf[2] = buf[3] =0x00; + fts_i2c_read(client, buf, 4, reg_val, 2); + + FTS_DEBUG("[UPGRADE] Read ROM/PRAM/Bootloader id:0x%02x%02x", reg_val[0], reg_val[1]); + if ((reg_val[0] == 0x00) || (reg_val[0] == 0xFF)) + { + inRomBoot = FTS_RUN_IN_ERROR; + } + else if (reg_val[0] == chip_types.pramboot_idh && reg_val[1] == chip_types.pramboot_idl) + { + inRomBoot = FTS_RUN_IN_PRAM; + } + else if (reg_val[0] == chip_types.rom_idh && reg_val[1] == chip_types.rom_idl) + { + inRomBoot = FTS_RUN_IN_ROM; + } + else if (reg_val[0] == chip_types.bootloader_idh && reg_val[1] == chip_types.bootloader_idl) + { + inRomBoot = FTS_RUN_IN_BOOTLOADER; + } + + return inRomBoot; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_file +* Brief: get app file by Vendor ID +* Input: +* Output: +* Return: <0: vendor id not correct,not upgrade +***********************************************************************/ +int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret; + + if (fts_updatefun_curr.get_i_file) + ret = fts_updatefun_curr.get_i_file(client, fw_valid); + else + ret = -EIO; + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_ver +* Brief: get app file version +* Input: +* Output: +* Return: fw version +***********************************************************************/ +int fts_ctpm_get_app_ver(void) +{ + int i_ret = 0; + + if (fts_updatefun_curr.get_app_i_file_ver) + i_ret = fts_updatefun_curr.get_app_i_file_ver(); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade +* Brief: fw upgrade entry funciotn +* Input: +* Output: +* Return: 0 - upgrade successfully +* <0 - upgrade failed +***********************************************************************/ +int fts_ctpm_fw_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + if (fts_updatefun_curr.upgrade_with_app_i_file) + i_ret = fts_updatefun_curr.upgrade_with_app_i_file(client); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade +* Brief: fw upgrade entry funciotn +* Input: +* Output: +* Return: 0 - upgrade successfully +* <0 - upgrade failed +***********************************************************************/ +int fts_ctpm_lcd_cfg_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + if (fts_updatefun_curr.upgrade_with_lcd_cfg_i_file) + i_ret = fts_updatefun_curr.upgrade_with_lcd_cfg_i_file(client); + + return i_ret; +} + +bool fts_check_fw_valid(struct i2c_client *client) +{ + int i = 0; + u8 chip_id = 0; + + for (i = 0; i < 3; i++) + { + fts_i2c_read_reg(client, FTS_REG_CHIP_ID, &chip_id); + if(chip_id == chip_types.chip_idh) + return true; + } + + return false; +} + +#if (!(FTS_UPGRADE_STRESS_TEST)) +/************************************************************************ +* Name: fts_ctpm_check_fw_status +* Brief: Check App is valid or not +* Input: +* Output: +* Return: -EIO - I2C communication error +* FTS_RUN_IN_APP - APP valid +* 0 - APP invalid +***********************************************************************/ +static int fts_ctpm_check_fw_status(struct i2c_client *client) +{ + u8 chip_id1 = 0; + u8 chip_id2 = 0; + int fw_status = FTS_RUN_IN_ERROR; + int i = 0; + int ret = 0; + int i2c_noack_retry = 0; + + for (i = 0; i < 5; i++) + { + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, &chip_id1); + if (ret < 0) + { + i2c_noack_retry++; + continue; + } + ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID2, &chip_id2); + if (ret < 0) + { + i2c_noack_retry++; + continue; + } + + if ((chip_id1 == chip_types.chip_idh) +#if FTS_CHIP_IDC + && (chip_id2 == chip_types.chip_idl) +#endif + ) + { + fw_status = FTS_RUN_IN_APP; + break; + } + } + + FTS_DEBUG("[UPGRADE]: chip_id = %02x%02x, chip_types.chip_idh = %02x%02x", + chip_id1, chip_id2, chip_types.chip_idh, chip_types.chip_idl); + + /* I2C No ACK 5 times, then return -EIO */ + if (i2c_noack_retry >= 5) + return -EIO; + + /* I2C communication ok, but not get correct ID, need check pram/rom/bootloader */ + if (i >= 5) + { + fw_status = fts_ctpm_get_pram_or_rom_id(client); + } + + return fw_status; +} + +/************************************************************************ +* Name: fts_ctpm_check_fw_ver +* Brief: Check vendor id is valid or not +* Input: +* Output: +* Return: 1 - vendor id valid +* 0 - vendor id invalid +***********************************************************************/ +static int fts_ctpm_check_fw_ver(struct i2c_client *client) +{ + u8 uc_tp_fm_ver; + u8 uc_host_fm_ver = 0; + + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + uc_host_fm_ver = fts_ctpm_get_app_ver(); + + FTS_DEBUG("[UPGRADE]: uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x!!", uc_tp_fm_ver, uc_host_fm_ver); + if (uc_tp_fm_ver < uc_host_fm_ver ) + { + return 1; + } + else + { + return 0; + } +} + +/************************************************************************ +* Name: fts_ctpm_check_need_upgrade +* Brief: +* Input: +* Output: +* Return: 1 - Need upgrade +* 0 - No upgrade +***********************************************************************/ +static int fts_ctpm_check_need_upgrade(struct i2c_client *client) +{ + int fw_status = 0; + int bUpgradeFlag = false; + + FTS_FUNC_ENTER(); + + /* 1. veriry FW APP is valid or not */ + fw_status = fts_ctpm_check_fw_status(client); + FTS_DEBUG( "[UPGRADE]: fw_status = %d!!", fw_status); + if (fw_status < 0) + { + /* I2C no ACK, return immediately */ + FTS_ERROR("[UPGRADE]******I2C NO ACK,exit upgrade******"); + return -EIO; + } + else if (fw_status == FTS_RUN_IN_ERROR) + { + FTS_ERROR("[UPGRADE]******IC Type Fail******"); + } + else if (fw_status == FTS_RUN_IN_APP) + { + FTS_INFO("[UPGRADE]**********FW APP valid**********"); + + if (fts_ctpm_get_i_file(client, 1) != 0) + { + FTS_DEBUG("[UPGRADE]******Get upgrade file(fw) fail******"); + return -EIO; + } + + if (fts_ctpm_check_fw_ver(client) == 1) + { + FTS_DEBUG("[UPGRADE]**********need upgrade fw**********"); + bUpgradeFlag = true; + } + else + { + FTS_DEBUG("[UPGRADE]**********Don't need upgrade fw**********"); + bUpgradeFlag = false; + } + } + else + { + /* if app is invalid, reset to run ROM */ + FTS_INFO("[UPGRADE]**********FW APP invalid**********"); + fts_ctpm_rom_or_pram_reset(client); + if (fts_ctpm_get_i_file(client, 0) != 0) + { + FTS_DEBUG("[UPGRADE]******Get upgrade file(flash) fail******"); + fts_ctpm_rom_or_pram_reset(client); + return -EIO; + } + fts_ctpm_rom_or_pram_reset(client); + bUpgradeFlag = true; + } + + FTS_FUNC_EXIT(); + + return bUpgradeFlag; +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: auto upgrade +* Input: +* Output: +* Return: 0 - no upgrade +***********************************************************************/ +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + u8 uc_tp_fm_ver; + int i_ret = 0; + int bUpgradeFlag = false; + u8 uc_upgrade_times = 0; + + FTS_DEBUG("[UPGRADE]********************check upgrade need or not********************"); + bUpgradeFlag = fts_ctpm_check_need_upgrade(client); + FTS_DEBUG("[UPGRADE]**********bUpgradeFlag = 0x%x**********", bUpgradeFlag); + + if (bUpgradeFlag <= 0) + { + FTS_DEBUG("[UPGRADE]**********No Upgrade, exit**********"); + return 0; + } + else + { + /* FW Upgrade */ + do + { + uc_upgrade_times++; + FTS_DEBUG("[UPGRADE]********************star upgrade(%d)********************", uc_upgrade_times); + + i_ret = fts_ctpm_fw_upgrade(client); + if (i_ret == 0) + { + /* upgrade success */ + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + FTS_DEBUG("[UPGRADE]********************Success upgrade to new fw version 0x%x********************", uc_tp_fm_ver); + + fts_ctpm_auto_clb(client); + break; + } + else + { + /* upgrade fail, reset to run ROM BOOT.. + * if app in flash is ok, TP will work success + */ + FTS_ERROR("[UPGRADE]********************upgrade fail, reset now********************"); + fts_ctpm_rom_or_pram_reset(client); + } + } + while (uc_upgrade_times < 2); /* if upgrade fail, upgrade again. then return */ + } + + return i_ret; +} +#endif + +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN +int fts_get_host_lic_ver(u8* ver) +{ + int i_ret = 0; + + if (fts_updatefun_curr.get_hlic_ver) + i_ret = fts_updatefun_curr.get_hlic_ver(); + + if (i_ret > 0) + *ver = i_ret; + return i_ret; +} + +/* check if lcd init code need upgrade +* true-need false-no need +*/ +static bool fts_lic_need_upgrade(struct i2c_client *client) +{ + int ret = 0; + u8 initcode_ver_in_tp = 0; + u8 initcode_ver_in_host = 0; + bool fwvalid = false; + + fwvalid = fts_check_fw_valid(client); + if( !fwvalid) { + FTS_INFO("fw is invalid, no upgrade lcd init code"); + return false; + } + + ret = fts_get_host_lic_ver(&initcode_ver_in_host); + if(ret < 0) + { + FTS_ERROR("init code in host invalid"); + return false; + } + + ret = fts_i2c_read_reg(client, 0xE4, &initcode_ver_in_tp); + if (ret < 0) { + FTS_ERROR("read reg0xE4 fail"); + return false; + } + + FTS_DEBUG("tp init ver:%x, fw init ver:%x", initcode_ver_in_tp, initcode_ver_in_host); + if(0xA5 == initcode_ver_in_tp) { + FTS_INFO("lcd init code ver is 0xA5, don't upgade init code"); + return false; + } + else if(0xFF == initcode_ver_in_tp) { + FTS_DEBUG("lcd init code in tp is invalid, need upgrade init code"); + return true; + } + else if(initcode_ver_in_tp < initcode_ver_in_host) + return true; + else + return false; +} + +int fts_lic_upgrade(struct i2c_client *client) +{ + int ret = 0; + bool hlic_upgrade = false; + int upgrade_count = 0; + + hlic_upgrade = fts_lic_need_upgrade(client); + FTS_INFO("lcd init code upgrade flag:%d", hlic_upgrade); + if(hlic_upgrade) { + FTS_INFO("lcd init code upgrade..."); + do { + upgrade_count++; + ret = fts_ctpm_lcd_cfg_upgrade(client); + if(0 == ret) { + FTS_INFO("lcd init code upgrade succussfully"); + break; + } + else { + fts_ctpm_rom_or_pram_reset(client); + } + }while (upgrade_count < 2); + } + + return ret; +} +#endif /* FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN */ + +#if FTS_AUTO_UPGRADE_EN +static void fts_ctpm_update_work_func(struct work_struct *work) +{ + int i_ret = 0; + + FTS_DEBUG( "[UPGRADE]******************************FTS enter upgrade******************************"); + fts_irq_disable(); + + /* esd check */ +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(DISABLE); +#endif + + i_ret = fts_ctpm_auto_upgrade(fts_i2c_client); + if (i_ret < 0) + FTS_ERROR("[UPGRADE]**********TP FW upgrade failed**********"); + +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN + i_ret = fts_lic_upgrade(fts_i2c_client); + if (i_ret < 0) + FTS_ERROR("**********lcd init code upgrade failed**********"); +#endif + +#if FTS_ESDCHECK_EN + fts_esdcheck_switch(ENABLE); +#endif + fts_irq_enable(); + + FTS_DEBUG( "[UPGRADE]******************************FTS exit upgrade******************************"); +} + +/***************************************************************************** +* Name: fts_ctpm_upgrade_init +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_ctpm_upgrade_init(void) +{ + FTS_FUNC_ENTER(); + + touch_wq = create_singlethread_workqueue("touch_wq"); + if (touch_wq) + { + INIT_WORK(&fw_update_work, fts_ctpm_update_work_func); + queue_work(touch_wq, &fw_update_work); + } + else + { + FTS_ERROR("[UPGRADE]create_singlethread_workqueue failed\n"); + } + + FTS_FUNC_EXIT(); +} + +/***************************************************************************** +* Name: fts_ctpm_upgrade_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_ctpm_upgrade_exit(void) +{ + FTS_FUNC_ENTER(); + destroy_workqueue(touch_wq); + FTS_FUNC_EXIT(); +} + +#endif /* #if FTS_AUTO_UPGRADE_EN */ diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.h b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.h new file mode 100755 index 000000000000..0270074cb4f3 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash.h @@ -0,0 +1,120 @@ +/************************************************************************ +* Copyright (C) 2010-2017, Focaltech Systems (R)٬All Rights Reserved. +* +* File Name: focaltech_flash.h +* +* Author: fupeipei +* +* Created: 2016-08-07 +* +* Abstract: +* +************************************************************************/ +#ifndef __LINUX_FOCALTECH_FLASH_H__ +#define __LINUX_FOCALTECH_FLASH_H__ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_flash/focaltech_upgrade_common.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define FTS_REG_ECC 0xCC +#define FTS_RST_CMD_REG2 0xBC +#define FTS_READ_ID_REG 0x90 +#define FTS_ERASE_APP_REG 0x61 +#define FTS_ERASE_PARAMS_CMD 0x63 +#define FTS_FW_WRITE_CMD 0xBF +#define FTS_REG_RESET_FW 0x07 +#define FTS_RST_CMD_REG1 0xFC +#define LEN_FLASH_ECC_MAX 0xFFFE + +#define FTS_PACKET_LENGTH 128 +#define FTS_SETTING_BUF_LEN 128 + +#define FTS_UPGRADE_LOOP 30 +#define AUTO_CLB_NEED 1 +#define AUTO_CLB_NONEED 0 +#define FTS_UPGRADE_AA 0xAA +#define FTS_UPGRADE_55 0x55 +#define FTXXXX_INI_FILEPATH_CONFIG "/sdcard/" + +enum FW_STATUS +{ + FTS_RUN_IN_ERROR, + FTS_RUN_IN_APP, + FTS_RUN_IN_ROM, + FTS_RUN_IN_PRAM, + FTS_RUN_IN_BOOTLOADER +}; + +enum FILE_SIZE_TYPE +{ + FW_SIZE, + FW2_SIZE, + FW3_SIZE, + PRAMBOOT_SIZE, +}; + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* IC info */ + +struct fts_upgrade_fun +{ + int (*get_i_file)(struct i2c_client *, int); + int (*get_app_bin_file_ver)(char *); + int (*get_app_i_file_ver)(void); + int (*upgrade_with_app_i_file)(struct i2c_client *); + int (*upgrade_with_app_bin_file)(struct i2c_client *, char *); + int (*get_hlic_ver)(void); + int (*upgrade_with_lcd_cfg_i_file)(struct i2c_client *); + int (*upgrade_with_lcd_cfg_bin_file)(struct i2c_client *, char *); +}; +extern struct fts_upgrade_fun fts_updatefun; + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +extern u8 CTPM_FW[]; +extern u8 CTPM_FW2[]; +extern u8 CTPM_FW3[]; +extern u8 aucFW_PRAM_BOOT[]; +extern u8 CTPM_LCD_CFG[]; +extern u8 *g_fw_file; +extern int g_fw_len; +extern struct fts_upgrade_fun fts_updatefun_curr; +extern struct ft_chip_t chip_types; + +#if FTS_AUTO_UPGRADE_EN +extern struct workqueue_struct *touch_wq; +extern struct work_struct fw_update_work; +#endif + +void fts_ctpm_upgrade_init(void); +void fts_ctpm_upgrade_exit(void); +void fts_ctpm_upgrade_delay(u32 i); +void fts_ctpm_get_upgrade_array(void); +int fts_ctpm_auto_upgrade(struct i2c_client *client); +int fts_fw_upgrade(struct device *dev, bool force); +int fts_ctpm_auto_clb(struct i2c_client *client); + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +u32 fts_getsize(u8 fw_type); +int fts_GetFirmwareSize(char *firmware_name); +int fts_ctpm_i2c_hid2std(struct i2c_client *client); +int fts_ReadFirmware(char *firmware_name,u8 *firmware_buf); +void fts_ctpm_rom_or_pram_reset(struct i2c_client *client); +enum FW_STATUS fts_ctpm_get_pram_or_rom_id(struct i2c_client *client); +#endif + + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/Makefile b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/Makefile new file mode 100755 index 000000000000..ee5c823ee997 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the focaltech touchscreen drivers. +# + +# Each configuration option enables a list of files. + + +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_upgrade_idc.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_upgrade_ft7250.o +obj-$(CONFIG_AMLOGIC_TOUCHSCREEN_FTS) += focaltech_upgrade_test.o diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h new file mode 100755 index 000000000000..8b522b250b2e --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_common.h @@ -0,0 +1,56 @@ +/************************************************************************ +* Copyright (C) 2010-2017, Focaltech Systems (R)٬All Rights Reserved. +* +* File Name: focaltech_upgrade_common.h +* +* Author: fupeipei +* +* Created: 2016-08-16 +* +* Abstract: +* +************************************************************************/ +#ifndef __LINUX_FOCALTECH_UPGRADE_COMMON_H__ +#define __LINUX_FOCALTECH_UPGRADE_COMMON_H__ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_flash.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +int fts_ctpm_erase_flash(struct i2c_client *client); +int fts_ctpm_pramboot_ecc(struct i2c_client *client); +bool fts_ctpm_check_run_state(struct i2c_client *client, int state); +void fts_ctpm_start_pramboot(struct i2c_client *client); +int fts_ctpm_start_fw_upgrade(struct i2c_client *client); +bool fts_ctpm_check_in_pramboot(struct i2c_client *client); +int fts_ctpm_upgrade_idc_init(struct i2c_client *client); +int fts_ctpm_write_app_for_idc(struct i2c_client *client, u32 length, u8 *readbuf); +int fts_ctpm_upgrade_ecc(struct i2c_client *client, u32 startaddr, u32 length); +int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client, u32 length, u8 *readbuf); +int fts_writeflash(struct i2c_client *client, u32 writeaddr, u32 length, u8 *readbuf, u32 cnt); + +int fts_ctpm_get_app_ver(void); +int fts_ctpm_fw_upgrade(struct i2c_client *client); +int fts_ctpm_lcd_cfg_upgrade(struct i2c_client *client); + +#endif diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7250.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7250.c new file mode 100755 index 000000000000..2a57b315a324 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_ft7250.c @@ -0,0 +1,1350 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_upgrade_ft7250.c +* +* Author: fupeipei +* +* Created: 2016-08-15 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" +#include "../focaltech_flash.h" +#include "focaltech_upgrade_common.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN +#define APP_OFFSET 0x5000 +#define APP_FILE_MAX_SIZE (116 * 1024) +#else +#define APP_OFFSET 0x0 +#define APP_FILE_MAX_SIZE (96 * 1024) +#endif + +#define APP_FILE_MIN_SIZE (8) +#define APP_FILE_VER_MAPPING (0x10E + APP_OFFSET) +#define APP_FILE_VENDORID_MAPPING (0x10C + APP_OFFSET) +#define APP_FILE_CHIPID_MAPPING (0x11E + APP_OFFSET) +#define CONFIG_START_ADDR (0xF80) +#define CONFIG_START_ADDR_LEN (0x80) +#define CONFIG_VENDOR_ID_OFFSET (0x04) +#define CONFIG_PROJECT_ID_OFFSET (0x20) +#define CONFIG_VENDOR_ID_ADDR (CONFIG_START_ADDR+CONFIG_VENDOR_ID_OFFSET) +#define CONFIG_PROJECT_ID_ADDR (CONFIG_START_ADDR+CONFIG_PROJECT_ID_OFFSET) +#define LCD_CFG_MAX_SIZE (4 * 1024) +#define LCD_CFG_MIN_SIZE (8) + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid); +static int fts_ctpm_get_app_i_file_ver(void); +static int fts_ctpm_get_app_bin_file_ver(char *firmware_name); +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client); +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, char *firmware_name); +static int fts_ctpm_fw_upgrade_with_lcd_cfg_i_file(struct i2c_client *client); +static int fts_get_host_lic_ver(void); + +struct fts_upgrade_fun fts_updatefun = +{ + .get_i_file = fts_ctpm_get_i_file, + .get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver, + .get_app_i_file_ver = fts_ctpm_get_app_i_file_ver, + .upgrade_with_app_i_file = fts_ctpm_fw_upgrade_with_app_i_file, + .upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file, + .get_hlic_ver = fts_get_host_lic_ver, + .upgrade_with_lcd_cfg_i_file = fts_ctpm_fw_upgrade_with_lcd_cfg_i_file, +}; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_GET_VENDOR_ID_NUM != 0) +/************************************************************************ +* Name: fts_ctpm_get_vendor_id_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client, u8 *vendor_id) +{ + bool inbootloader = false; + u8 rw_buf[10]; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) + { + FTS_ERROR( "[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + msleep(10); + + inbootloader = fts_ctpm_check_run_state(client, FTS_RUN_IN_BOOTLOADER); + if (!inbootloader) + { + FTS_ERROR( "[UPGRADE]: not run in bootloader, upgrade fail!!"); + return -EIO; + } + + /*read vendor id*/ + rw_buf[0] = 0x03; + rw_buf[1] = 0x00; + rw_buf[2] = (u8)(CONFIG_VENDOR_ID_ADDR >> 8); + rw_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR); + i_ret = fts_i2c_write(client, rw_buf, 4); + msleep(10); /* must wait, otherwise read vendor id wrong */ + i_ret = fts_i2c_read(client, NULL, 0, vendor_id, 1); + if (i_ret < 0) + { + return -EIO; + } + FTS_DEBUG("Vendor ID from Flash:%x", *vendor_id); + return 0; +} +#endif + +/************************************************************************ +* Name: fts_ft5x46_get_i_file +* Brief: get .i file +* Input: +* Output: +* Return: 0 - ok +* <0 - fail +***********************************************************************/ +static int fts_ctpm_get_i_file(struct i2c_client *client, int fw_valid) +{ + int ret = 0; + +#if (FTS_GET_VENDOR_ID_NUM != 0) + u8 vendor_id = 0; + + if (fw_valid) + ret = fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id); + else + ret = fts_ctpm_get_vendor_id_flash(client, &vendor_id); + if (ret < 0) + { + FTS_ERROR("Get upgrade file fail because of Vendor ID wrong"); + return ret; + } + FTS_INFO("[UPGRADE] vendor id in tp=%x", vendor_id); + FTS_INFO("[UPGRADE] vendor id in driver:%x, FTS_VENDOR_ID:%02x %02x %02x", + vendor_id, FTS_VENDOR_1_ID, FTS_VENDOR_2_ID, FTS_VENDOR_3_ID); + + ret = 0; + switch (vendor_id) + { +#if (FTS_GET_VENDOR_ID_NUM >= 1) + case FTS_VENDOR_1_ID: + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 2) + case FTS_VENDOR_2_ID: + g_fw_file = CTPM_FW2; + g_fw_len = fts_getsize(FW2_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW2, SIZE:%x", g_fw_len); + break; +#endif +#if (FTS_GET_VENDOR_ID_NUM >= 3) + case FTS_VENDOR_3_ID: + g_fw_file = CTPM_FW3; + g_fw_len = fts_getsize(FW3_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW3, SIZE:%x", g_fw_len); + break; +#endif + default: + FTS_ERROR("[UPGRADE]Vendor ID check fail, get fw file fail"); + ret = -EIO; + break; + } +#else + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); +#endif + + return ret; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_bin_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_bin_file_ver(char *firmware_name) +{ + u8 *pbt_buf = NULL; + int fwsize = 0; + int fw_ver = 0; + + FTS_FUNC_ENTER(); + + fwsize = fts_GetFirmwareSize(firmware_name); + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) + { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return -EIO; + } + + pbt_buf = (unsigned char *)kmalloc(fwsize + 1, GFP_KERNEL); + if (fts_ReadFirmware(firmware_name, pbt_buf)) + { + FTS_ERROR("[UPGRADE]: request_firmware failed!!"); + kfree(pbt_buf); + return -EIO; + } + + fw_ver = pbt_buf[APP_FILE_VER_MAPPING]; + + kfree(pbt_buf); + FTS_FUNC_EXIT(); + + return fw_ver; +} + +/************************************************************************ +* Name: fts_ctpm_get_app_i_file_ver +* Brief: get .i file version +* Input: no +* Output: no +* Return: fw version +***********************************************************************/ +static int fts_ctpm_get_app_i_file_ver(void) +{ + int fwsize = g_fw_len; + + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) + { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fwsize); + return 0; + } + + return g_fw_file[APP_FILE_VER_MAPPING]; +} + +/* read host lcd init code ver +* return 0 if host lcd init code is valid, otherwise return error code +*/ +static int fts_get_host_lic_ver(void) +{ + u8 *hlic_buf = g_fw_file; + u32 hlic_len = 0; + u8 hlic_ver[2] = { 0 }; + u32 upgfile_len = g_fw_len; + + if(upgfile_len < 4096) + { + FTS_ERROR("upgrade file len fail"); + return -EINVAL; + } + hlic_len = (u32)(((u32)hlic_buf[2]) << 8) + hlic_buf[3]; + FTS_DEBUG("host lcd init code len:%x", hlic_len); + if(hlic_len >= upgfile_len) + { + FTS_ERROR("host lcd init code len is too large"); + return -EINVAL; + } + + hlic_ver[0] = hlic_buf[hlic_len]; + hlic_ver[1] = hlic_buf[hlic_len + 1]; + + FTS_DEBUG("host lcd init code ver:%x %x", hlic_ver[0], hlic_ver[1]); + if(0xFF != (hlic_ver[0] + hlic_ver[1])) + { + FTS_ERROR("host lcd init code version check fail"); + return -EINVAL; + } + + return hlic_ver[0]; +} + +//3-gamma begin +#define MAX_BANK_DATA 0x80 +#define MAX_GAMMA_LEN 0x180 +int gamma_analog[] = { 0x003A, 0x85, 0x00, 0x00, 0x2C, 0x2B }; +int gamma_digital1[] = { 0x0355, 0x8D, 0x00, 0x00, 0x80, 0x80 }; +int gamma_digital2[] = { 0x03d9, 0x8D, 0x80, 0x00, 0x14, 0x13 }; +int gamma_enable[] = { 0x040d, 0x91, 0x80, 0x00, 0x19, 0x01 }; +union short_bits{ + u16 dshort; + struct bits{ + u16 bit0:1; + u16 bit1:1; + u16 bit2:1; + u16 bit3:1; + u16 bit4:1; + u16 bit5:1; + u16 bit6:1; + u16 bit7:1; + u16 bit8:1; + u16 bit9:1; + u16 bit10:1; + u16 bit11:1; + u16 bit12:1; + u16 bit13:1; + u16 bit14:1; + u16 bit15:1; + }bits; +}; + +/* calculate lcd init code ecc */ +static int cal_lcdinitcode_ecc(u8 *buf, u16 *ecc_val) +{ + u32 bank_crc_en = 0; + u8 bank_data[MAX_BANK_DATA] = { 0 }; + u16 bank_len = 0; + u16 bank_addr = 0; + u32 bank_num = 0; + u16 file_len = 0; + u16 pos = 0; + int i = 0; + union short_bits ecc; + union short_bits ecc_last; + union short_bits temp_byte; + u8 bank_mapping[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, + 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x10, 0x11, 0x12, 0x13, 0x14, 0x18, + 0x19, 0x1A, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x22, 0x23, 0x24}; //Actaul mipi bank + u8 banknum = 0; + + ecc.dshort = 0; + ecc_last.dshort = 0; + temp_byte.dshort = 0; + + file_len = (u16)(((u16)buf[2] << 8) + buf[3]); + bank_crc_en = (u32)(((u32)buf[9] << 24) + ((u32)buf[8] << 16) +\ + ((u32)buf[7] << 8) + (u32)buf[6]); + FTS_INFO("lcd init code len=%x bank en=%x", file_len, bank_crc_en); + + pos = 0x0A; // addr of first bank + while(pos < file_len) + { + bank_addr = (u16)(((u16)buf[pos + 0] << 8 ) + buf[pos + 1]); + bank_len = (u16)(((u16)buf[pos + 2] << 8 ) + buf[pos + 3]); + FTS_INFO("bank pos=%x bank_addr=%x bank_len=%x", pos, bank_addr, bank_len); + if(bank_len > MAX_BANK_DATA) + return -EINVAL; + memset(bank_data, 0, MAX_BANK_DATA); + memcpy(bank_data, buf + pos + 4, bank_len); + + bank_num = (bank_addr - 0x8000)/MAX_BANK_DATA; + FTS_INFO("actual mipi bank number = %x", bank_num); + for(i = 0; i < sizeof(bank_mapping)/sizeof(u8); i++) + { + if(bank_num == bank_mapping[i]) + { + banknum = i; + break; + } + } + if(i >= sizeof(bank_mapping)/sizeof(u8)) + { + FTS_INFO("actual mipi bank(%d) not find in bank mapping, need jump", bank_num); + } + else{ + FTS_INFO("bank number = %d", banknum); + if((bank_crc_en >> banknum) & 0x01) + { + for(i = 0; i < MAX_BANK_DATA; i++) + { + temp_byte.dshort = (u16)bank_data[i]; + if(i == 0) + FTS_INFO("data0=%x, %d %d %d %d %d %d %d %d", temp_byte.dshort, temp_byte.bits.bit0, + temp_byte.bits.bit1, temp_byte.bits.bit2, temp_byte.bits.bit3, temp_byte.bits.bit4, + temp_byte.bits.bit5, temp_byte.bits.bit6, temp_byte.bits.bit7); + + ecc.bits.bit0 = ecc_last.bits.bit8 ^ ecc_last.bits.bit9 ^ ecc_last.bits.bit10 ^ ecc_last.bits.bit11 + ^ ecc_last.bits.bit12 ^ ecc_last.bits.bit13 ^ ecc_last.bits.bit14 ^ ecc_last.bits.bit15 + ^ temp_byte.bits.bit0 ^ temp_byte.bits.bit1 ^ temp_byte.bits.bit2 ^ temp_byte.bits.bit3 + ^ temp_byte.bits.bit4 ^ temp_byte.bits.bit5 ^ temp_byte.bits.bit6 ^ temp_byte.bits.bit7; + + ecc.bits.bit1 = ecc_last.bits.bit9 ^ ecc_last.bits.bit10 ^ ecc_last.bits.bit11 ^ ecc_last.bits.bit12 + ^ ecc_last.bits.bit13 ^ ecc_last.bits.bit14 ^ ecc_last.bits.bit15 + ^ temp_byte.bits.bit1 ^ temp_byte.bits.bit2 ^ temp_byte.bits.bit3 ^ temp_byte.bits.bit4 + ^ temp_byte.bits.bit5 ^ temp_byte.bits.bit6 ^ temp_byte.bits.bit7; + + ecc.bits.bit2 = ecc_last.bits.bit8 ^ ecc_last.bits.bit9 ^ temp_byte.bits.bit0 ^ temp_byte.bits.bit1; + + ecc.bits.bit3 = ecc_last.bits.bit9 ^ ecc_last.bits.bit10 ^ temp_byte.bits.bit1 ^ temp_byte.bits.bit2; + + ecc.bits.bit4 = ecc_last.bits.bit10 ^ ecc_last.bits.bit11 ^ temp_byte.bits.bit2 ^ temp_byte.bits.bit3; + + ecc.bits.bit5 = ecc_last.bits.bit11 ^ ecc_last.bits.bit12 ^ temp_byte.bits.bit3 ^ temp_byte.bits.bit4; + + ecc.bits.bit6 = ecc_last.bits.bit12 ^ ecc_last.bits.bit13 ^ temp_byte.bits.bit4 ^ temp_byte.bits.bit5; + + ecc.bits.bit7 = ecc_last.bits.bit13 ^ ecc_last.bits.bit14 ^ temp_byte.bits.bit5 ^ temp_byte.bits.bit6; + + ecc.bits.bit8 = ecc_last.bits.bit0 ^ ecc_last.bits.bit14^ ecc_last.bits.bit15 ^ temp_byte.bits.bit6 ^ temp_byte.bits.bit7; + + ecc.bits.bit9 = ecc_last.bits.bit1 ^ ecc_last.bits.bit15 ^ temp_byte.bits.bit7; + + ecc.bits.bit10 = ecc_last.bits.bit2; + + ecc.bits.bit11 = ecc_last.bits.bit3; + + ecc.bits.bit12 = ecc_last.bits.bit4; + + ecc.bits.bit13 = ecc_last.bits.bit5; + + ecc.bits.bit14 = ecc_last.bits.bit6; + + ecc.bits.bit15 = ecc_last.bits.bit7 ^ ecc_last.bits.bit8 ^ ecc_last.bits.bit9 ^ ecc_last.bits.bit10 + ^ ecc_last.bits.bit11 ^ ecc_last.bits.bit12 ^ ecc_last.bits.bit13 ^ ecc_last.bits.bit14 ^ ecc_last.bits.bit15 + ^ temp_byte.bits.bit0 ^ temp_byte.bits.bit1 ^ temp_byte.bits.bit2 ^ temp_byte.bits.bit3 + ^ temp_byte.bits.bit4 ^ temp_byte.bits.bit5 ^ temp_byte.bits.bit6 ^ temp_byte.bits.bit7; + + ecc_last.dshort = ecc.dshort; + + } + } + } + pos += bank_len + 4; + } + + *ecc_val = ecc.dshort; + FTS_INFO(""); + return 0; +} + +/* calculate lcd init code checksum */ +static unsigned short cal_lcdinitcode_checksum(u8 *ptr , int length) +{ + //CRC16 + u16 cFcs = 0; + int i, j; + + if (length%2) + { + return 0xFFFF; + } + + for ( i = 0; i < length; i += 2 ) + { + cFcs ^= ((ptr[i] << 8) + ptr[i+1]); + for (j = 0; j < 16; j ++) + { + if (cFcs & 1) + { + cFcs = (unsigned short)((cFcs >> 1) ^ ((1 << 15) + (1 << 10) + (1 << 3))); + } + else + { + cFcs >>= 1; + } + } + } + return cFcs; +} + +static int print_data(u8 *buf, u32 len) +{ + int i = 0; + int n = 0; + u8 *p = NULL; + + p = kmalloc(len*4, GFP_KERNEL); + memset(p, 0, len*4); + + for (i = 0; i < len; i++) + { + n += sprintf(p + n, "%02x ", buf[i]); + } + + FTS_DEBUG("%s", p); + + kfree(p); + return 0; +} + +static int read_3gamma(struct i2c_client *client, u8 **gamma, u16 *len) +{ + int ret = 0; + int i = 0; + int packet_num = 0; + int packet_len = 0; + int remainder = 0; + u8 cmd[4] = { 0 }; + u32 addr = 0x01D000; + u8 gamma_header[0x20] = { 0 }; + u16 gamma_len = 0; + u16 gamma_len_n = 0; + u16 pos = 0; + bool gamma_has_enable = false; + u8 *pgamma = NULL; + int j = 0; + u8 gamma_ecc = 0; + + cmd[0] = 0x03; + cmd[1] = (u8)(addr >> 16); + cmd[2] = (u8)(addr >> 8); + cmd[3] = (u8)addr; + ret = fts_i2c_write(client, cmd, 4); + msleep(10); + ret = fts_i2c_read(client, NULL, 0, gamma_header, 0x20); + if(ret < 0) + { + FTS_ERROR("read 3-gamma header fail"); + return ret; + } + + gamma_len = (u16)((u16)gamma_header[0] << 8) + gamma_header[1]; + gamma_len_n = (u16)((u16)gamma_header[2] << 8) + gamma_header[3]; + + if((gamma_len + gamma_len_n) != 0xFFFF) + { + FTS_INFO("gamma length check fail:%x %x", gamma_len, gamma_len); + return -EIO; + } + + if((gamma_header[4] + gamma_header[5]) != 0xFF) + { + FTS_INFO("gamma ecc check fail:%x %x", gamma_header[4], gamma_header[5]); + return -EIO; + } + + if(gamma_len > MAX_GAMMA_LEN) + { + FTS_ERROR("gamma data len(%d) is too long", gamma_len); + return -EINVAL; + } + + *gamma = kmalloc(MAX_GAMMA_LEN, GFP_KERNEL); + if(NULL == *gamma) + { + FTS_ERROR("malloc gamma memory fail"); + return -ENOMEM; + } + pgamma = *gamma; + + packet_num = gamma_len/256; + packet_len = 256; + remainder = gamma_len%256; + if(remainder) packet_num++; + FTS_INFO("3-gamma len:%d", gamma_len); + cmd[0] = 0x03; + addr += 0x20; + for(i = 0; i < packet_num; i++) + { + addr += i * 256; + cmd[1] = (u8)(addr >> 16); + cmd[2] = (u8)(addr >> 8); + cmd[3] = (u8)addr; + if ((i == packet_num -1) && remainder) + packet_len = remainder; + ret = fts_i2c_write(client, cmd, 4); + msleep(10); + ret = fts_i2c_read(client, NULL, 0, pgamma + i*256, packet_len); + if(ret < 0) + { + FTS_ERROR("read 3-gamma data fail"); + return ret; + } + } + + + // ecc + for(j = 0; j < gamma_len; j++) + { + gamma_ecc ^= pgamma[j]; + } + FTS_INFO("back_3gamma_ecc: 0x%x, 0x%x",gamma_ecc,gamma_header[0x04]); + if(gamma_ecc != gamma_header[0x04]) + { + FTS_ERROR("back gamma ecc check fail:%x %x", gamma_ecc, gamma_header[0x04]); + return -EIO; + } + + + /* check last byte is 91 80 00 19 01 */ + pos = gamma_len - 5; + if((gamma_enable[1] == pgamma[pos]) && (gamma_enable[2] == pgamma[pos+1]) + && (gamma_enable[3] == pgamma[pos+2]) && (gamma_enable[4] == pgamma[pos+3])) + { + gamma_has_enable = true; + } + + if(false == gamma_has_enable) + { + FTS_INFO("3-gamma has no gamma enable info"); + pgamma[gamma_len++] = gamma_enable[1]; + pgamma[gamma_len++] = gamma_enable[2]; + pgamma[gamma_len++] = gamma_enable[3]; + pgamma[gamma_len++] = gamma_enable[4]; + pgamma[gamma_len++] = gamma_enable[5]; + } + + *len = gamma_len; + + FTS_DEBUG("read 3-gamma data:"); + print_data(*gamma, gamma_len); + + return 0; +} + +static int replace_3gamma(u8 *initcode, u8 *gamma, u16 gamma_len) +{ + u16 gamma_pos = 0; + + /* Analog Gamma */ + if((initcode[gamma_analog[0]] == gamma[gamma_pos]) + && (initcode[gamma_analog[0] + 1] == gamma[gamma_pos + 1])) + { + memcpy(initcode + gamma_analog[0] + 4 , gamma + gamma_pos + 4, gamma_analog[5]); + gamma_pos += gamma_analog[5] + 4; + } + else + goto find_gamma_bank_err; + + /* Digital1 Gamma */ + if((initcode[gamma_digital1[0]] == gamma[gamma_pos]) + && (initcode[gamma_digital1[0] + 1] == gamma[gamma_pos + 1])) + { + memcpy(initcode + gamma_digital1[0] + 4 , gamma + gamma_pos + 4, gamma_digital1[5]); + gamma_pos += gamma_digital1[5] + 4; + } + else + goto find_gamma_bank_err; + + /* Digital2 Gamma */ + if((initcode[gamma_digital2[0]] == gamma[gamma_pos]) + && (initcode[gamma_digital2[0] + 1] == gamma[gamma_pos + 1])) + { + memcpy(initcode + gamma_digital2[0] + 4 , gamma + gamma_pos + 4, gamma_digital2[5]); + gamma_pos += gamma_digital2[5] + 4; + } + else + goto find_gamma_bank_err; + + /* enable Gamma */ + if((initcode[gamma_enable[0]] == gamma[gamma_pos]) + && (initcode[gamma_enable[0] + 1] == gamma[gamma_pos + 1])) + { + if(gamma[gamma_pos + 4]) + initcode[gamma_enable[0] + 4 + 15] |= 0x01; + else + initcode[gamma_enable[0] + 4 + 15] &= 0xFE; + gamma_pos += 1 + 4; + } + else + goto find_gamma_bank_err; + + FTS_DEBUG("replace 3-gamma data:"); + print_data(initcode, 1100); + + return 0; + +find_gamma_bank_err: + FTS_INFO("3-gamma bank(%02x %02x) not find", + gamma[gamma_pos], gamma[gamma_pos+1]); + return -ENODATA; +} + +static int read_replace_3gamma(struct i2c_client *client, u8 *buf) +{ + int ret = 0; + u16 initcode_ecc = 0; + u16 initcode_checksum = 0; + u8 *gamma = NULL; + u16 gamma_len = 0; + + FTS_FUNC_ENTER(); + + ret = read_3gamma(client, &gamma, &gamma_len); + if(ret < 0) + { + FTS_INFO("no vaid 3-gamma data, not replace"); + return 0; + } + + ret = replace_3gamma(buf, gamma, gamma_len); + if(ret < 0) + { + FTS_ERROR("replace 3-gamma fail"); + kfree(gamma); + return ret; + } + + ret = cal_lcdinitcode_ecc(buf, &initcode_ecc); + if (ret < 0) + { + FTS_ERROR("lcd init code ecc calculate fail"); + kfree(gamma); + return ret; + } + FTS_INFO("lcd init code cal ecc:%04x", initcode_ecc); + buf[4] = (u8)(initcode_ecc >> 8); + buf[5] = (u8)(initcode_ecc); + buf[0x43d] = (u8)(initcode_ecc >> 8); + buf[0x43c] = (u8)(initcode_ecc); + + initcode_checksum = cal_lcdinitcode_checksum(buf + 2, 0x43e - 2); + FTS_INFO("lcd init code calc checksum:%04x", initcode_checksum); + buf[0] = (u8)(initcode_checksum >> 8); + buf[1] = (u8)(initcode_checksum); + + FTS_FUNC_EXIT(); + + kfree(gamma); + return 0; +} +//3-gamma end + +int check_initial_code_valid(struct i2c_client *client, u8 *buf) +{ + int ret = 0; + u16 initcode_ecc = 0; + u16 initcode_checksum = 0; + + initcode_checksum = cal_lcdinitcode_checksum(buf + 2, 0x43e - 2); + FTS_INFO("lcd init code calc checksum:%04x", initcode_checksum); + if (initcode_checksum != ((u16)((u16)buf[0] << 8) + buf[1])) + { + FTS_ERROR("Initial Code checksum fail"); + return -EINVAL; + } + + ret = cal_lcdinitcode_ecc(buf, &initcode_ecc); + if (ret < 0) + { + FTS_ERROR("lcd init code ecc calculate fail"); + return ret; + } + FTS_INFO("lcd init code cal ecc:%04x", initcode_ecc); + if(initcode_ecc != ((u16)((u16)buf[4] << 8) + buf[5])) + { + FTS_ERROR("Initial Code ecc check fail"); + return -EINVAL; + } + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client, u8 *pbt_buf, u32 dw_lenth) +{ + u8 reg_val[4] = {0}; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 lenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret = 0; + bool inbootloader = false; + + fts_ctpm_i2c_hid2std(client); + + i_ret = fts_ctpm_start_fw_upgrade(client); + if (i_ret < 0) + { + FTS_ERROR( "[UPGRADE]: send upgrade cmd to FW error!!"); + return i_ret; + } + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + msleep(10); + + inbootloader = fts_ctpm_check_run_state(client, FTS_RUN_IN_BOOTLOADER); + if (!inbootloader) + { + FTS_ERROR( "[UPGRADE]: not run in bootloader, upgrade fail!!"); + return -EIO; + } + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0B; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + /* + * All.bin <= 128K + * APP.bin <= 94K + * LCD_CFG <= 4K + */ + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = (u8) ((dw_lenth >> 16) & 0xFF); + auc_i2c_write_buf[2] = (u8) ((dw_lenth >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_lenth & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + + /*erase the app erea in flash*/ + i_ret = fts_ctpm_erase_flash(client); + if (i_ret < 0) + { + FTS_ERROR( "[UPGRADE]: erase flash error!!"); + return i_ret; + } + + /*write FW to ctpm flash*/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + + for (j = 0; j < packet_number; j++) + { + temp = 0x5000 + j * FTS_PACKET_LENGTH; + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (lenght >> 8); + packet_buf[5] = (u8) lenght; + for (i = 0; i < FTS_PACKET_LENGTH; i++) + { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + //msleep(1); + + for (i = 0; i < 30; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)) == (((reg_val[0]) << 8) | reg_val[1])) + { + break; + } + + if (i > 15) + { + msleep(1); + FTS_DEBUG("[UPGRADE]: write flash: host : %x status : %x!!", (j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)), (((reg_val[0]) << 8) | reg_val[1])); + } + //msleep(1); + fts_ctpm_upgrade_delay(10000); + } + } + + if ((dw_lenth) % FTS_PACKET_LENGTH > 0) + { + temp = 0x5000 + packet_number * FTS_PACKET_LENGTH; + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) + { + packet_buf[6 + i] = pbt_buf[packet_number * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + //msleep(1); + + for (i = 0; i < 30; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((0x5000 + packet_number * FTS_PACKET_LENGTH)/((dw_lenth) % FTS_PACKET_LENGTH))) == (((reg_val[0]) << 8) | reg_val[1])) + { + break; + } + + if (i > 15) + { + msleep(1); + FTS_DEBUG("[UPGRADE]: write flash: host : %x status : %x!!", (j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)), (((reg_val[0]) << 8) | reg_val[1])); + } + //msleep(1); + fts_ctpm_upgrade_delay(10000); + } + } + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0x5000; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = (64*1024-1); + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_lenth/256); + + temp = (0x5000+(64*1024-1)); + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = (dw_lenth-(64*1024-1)); + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_lenth/256); + + for (i = 0; i < 100; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0==reg_val[0] && 0x55==reg_val[1]) + { + FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", reg_val[0], reg_val[1]); + break; + } + msleep(1); + + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) + { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!",reg_val[0],upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum %x %x!!",reg_val[0],upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_use_buf +* Brief: fw upgrade +* Input: i2c info, file buf, file len +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_lcd_cfg_upgrade_use_buf(struct i2c_client * client, u8* pbt_buf, u32 dw_lenth) +{ + u8 reg_val[4] = {0}; + u32 i = 0; + u32 packet_number; + u32 j = 0; + u32 temp; + u32 lenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 upgrade_ecc; + int i_ret; + + fts_ctpm_i2c_hid2std(client); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) + { + /*write 0xaa to register FTS_RST_CMD_REG1 */ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + msleep(10); + + /*write 0x55 to register FTS_RST_CMD_REG1*/ + fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + /*Enter upgrade mode*/ + fts_ctpm_i2c_hid2std(client); + + msleep(10); + auc_i2c_write_buf[0] = FTS_UPGRADE_55; + auc_i2c_write_buf[1] = FTS_UPGRADE_AA; + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 2); + if (i_ret < 0) + { + FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa!!"); + continue; + } + + /*check run in bootloader or not*/ + msleep(1); + auc_i2c_write_buf[0] = FTS_READ_ID_REG; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] =0x00; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 4, reg_val, 2); + + if (reg_val[0] == chip_types.bootloader_idh + && reg_val[1] == chip_types.bootloader_idl) + { + FTS_DEBUG("[UPGRADE]: read bootload id ok!! ID1 = 0x%x,ID2 = 0x%x!!",reg_val[0], reg_val[1]); + break; + } + else + { + FTS_ERROR("[UPGRADE]: read bootload id fail!! ID1 = 0x%x,ID2 = 0x%x!!",reg_val[0], reg_val[1]); + continue; + } + } + + if (i >= FTS_UPGRADE_LOOP ) + return -EIO; + + + i_ret = read_replace_3gamma(client, pbt_buf); + if(i_ret < 0) + { + FTS_ERROR("replace 3-gamma fail, not upgrade lcd init code"); + return i_ret; + } + + i_ret = check_initial_code_valid(client, pbt_buf); + if(i_ret < 0) + { + FTS_ERROR("initial code invalid, not upgrade lcd init code"); + return i_ret; + } + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0C; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + /*Step 4:erase app and panel paramenter area*/ + FTS_DEBUG("[UPGRADE]: erase app and panel paramenter area!!"); + auc_i2c_write_buf[0] = FTS_ERASE_APP_REG; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + for (i = 0; i < 15; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + if (0xF0==reg_val[0] && 0xAA==reg_val[1]) + { + break; + } + msleep(50); + } + FTS_DEBUG("[UPGRADE]: erase app area reg_val[0] = %x reg_val[1] = %x!!", reg_val[0], reg_val[1]); + + auc_i2c_write_buf[0] = 0xB0; + auc_i2c_write_buf[1] = 0; + auc_i2c_write_buf[2] = (u8) ((dw_lenth >> 8) & 0xFF); + auc_i2c_write_buf[3] = (u8) (dw_lenth & 0xFF); + fts_i2c_write(client, auc_i2c_write_buf, 4); + + /*write FW to ctpm flash*/ + upgrade_ecc = 0; + FTS_DEBUG("[UPGRADE]: write FW to ctpm flash!!"); + temp = 0; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = FTS_FW_WRITE_CMD; + packet_buf[1] = 0; + for (j = 0; j < packet_number; j++) + { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (lenght >> 8); + packet_buf[5] = (u8) lenght; + for (i = 0; i < FTS_PACKET_LENGTH; i++) + { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, FTS_PACKET_LENGTH + 6); + //msleep(1); + + for (i = 0; i < 30; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x1000) == (((reg_val[0]) << 8) | reg_val[1])) + { + break; + } + + if (i > 15) + { + msleep(1); + FTS_DEBUG("[UPGRADE]: write flash: host : %x status : %x!!", (j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)), (((reg_val[0]) << 8) | reg_val[1])); + } + //msleep(1); + fts_ctpm_upgrade_delay(10000); + } + } + + if ((dw_lenth) % FTS_PACKET_LENGTH > 0) + { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + for (i = 0; i < temp; i++) + { + packet_buf[6 + i] = pbt_buf[packet_number * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + //msleep(1); + + for (i = 0; i < 30; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((0x1000 + ((packet_number * FTS_PACKET_LENGTH)/((dw_lenth) % FTS_PACKET_LENGTH))) == (((reg_val[0]) << 8) | reg_val[1])) + { + break; + } + + if (i > 15) + { + msleep(1); + FTS_DEBUG("[UPGRADE]: write flash: host : %x status : %x!!", (j + 0x1000 + (0x5000/FTS_PACKET_LENGTH)), (((reg_val[0]) << 8) | reg_val[1])); + } + //msleep(1); + fts_ctpm_upgrade_delay(10000); + } + } + + msleep(50); + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + FTS_DEBUG("[UPGRADE]: read out checksum!!"); + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + temp = 0x00; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = 0; + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = dw_lenth; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(dw_lenth/256); + + for (i = 0; i < 100; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0==reg_val[0] && 0x55==reg_val[1]) + { + FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", reg_val[0], reg_val[1]); + break; + } + msleep(1); + + } + auc_i2c_write_buf[0] = 0x66; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) + { + FTS_ERROR("[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!",reg_val[0],upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum %x %x!!",reg_val[0],upgrade_ecc); + + FTS_DEBUG("[UPGRADE]: reset the new FW!!"); + auc_i2c_write_buf[0] = FTS_REG_RESET_FW; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1000); + + fts_ctpm_i2c_hid2std(client); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: +* Return: fail < 0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with app.i**********"); + + fw_len = g_fw_len - APP_OFFSET; + fw_buf = g_fw_file + APP_OFFSET; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) + { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw_buf, fw_len); + if (i_ret != 0) + { + FTS_ERROR("[UPGRADE] upgrade app.i failed"); + } + else + { + FTS_INFO("[UPGRADE]: upgrade app.i succeed"); + } + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_lcd_cfg_i_file +* Brief: upgrade with *.i file +* Input: i2c info +* Output: no +* Return: fail <0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_lcd_cfg_i_file(struct i2c_client *client) +{ + int i_ret = 0; + u32 fw_len; + u8 *fw_buf; + + FTS_INFO("[UPGRADE]**********start upgrade with lcd init code**********"); + + fw_len = g_fw_len; + fw_buf = g_fw_file; + if (fw_len < APP_FILE_MIN_SIZE || fw_len > APP_FILE_MAX_SIZE) + { + FTS_ERROR("[UPGRADE]: FW length(%x) error", fw_len); + return -EIO; + } + + /*FW upgrade*/ + i_ret = fts_ctpm_lcd_cfg_upgrade_use_buf(client, fw_buf, 4096); + if (i_ret != 0) + { + FTS_ERROR("[UPGRADE] init code upgrade fail, ret=%d", i_ret); + } + else + { + FTS_INFO("[UPGRADE] init code upgrade succeed"); + } + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_fw_upgrade_with_app_bin_file +* Brief: upgrade with *.bin file +* Input: i2c info, file name +* Output: no +* Return: success =0 +***********************************************************************/ +static int fts_ctpm_fw_upgrade_with_app_bin_file(struct i2c_client *client, char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret=0; + int fwsize = 0; + + FTS_INFO("[UPGRADE]**********start upgrade with app.bin**********"); + + fwsize = fts_GetFirmwareSize(firmware_name); + if (fwsize < APP_FILE_MIN_SIZE || fwsize > APP_FILE_MAX_SIZE) + { + FTS_ERROR("[UPGRADE]: app.bin length(%x) error, upgrade fail", fwsize); + return -EIO; + } + + pbt_buf = (unsigned char *)kmalloc(fwsize + 1, GFP_KERNEL); + if (NULL == pbt_buf) + { + FTS_ERROR(" malloc pbt_buf failed "); + goto ERROR_BIN; + } + + if (fts_ReadFirmware(firmware_name, pbt_buf)) + { + FTS_ERROR("[UPGRADE]: request_firmware failed!!"); + goto ERROR_BIN; + } +#if FTS_AUTO_UPGRADE_FOR_LCD_CFG_EN + i_ret = fts_ctpm_lcd_cfg_upgrade_use_buf(client, pbt_buf, 4096); + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf + APP_OFFSET, fwsize - APP_OFFSET); +#else + i_ret = fts_ctpm_fw_upgrade_use_buf(client, pbt_buf, fwsize); +#endif + if (i_ret != 0) + { + FTS_ERROR("[UPGRADE]: upgrade app.bin failed"); + goto ERROR_BIN; + } + else + { + FTS_INFO("[UPGRADE]: upgrade app.bin succeed"); + } + + + kfree(pbt_buf); + return i_ret; +ERROR_BIN: + kfree(pbt_buf); + return -EIO; +} diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c new file mode 100755 index 000000000000..26bfeabb26e1 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_idc.c @@ -0,0 +1,461 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_upgrade_idc.c +* +* Author: fupeipei +* +* Created: 2016-08-22 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" + +#if (FTS_CHIP_IDC == 1) +#include "../focaltech_flash.h" + +/***************************************************************************** +* Static variables +*****************************************************************************/ + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +u8 upgrade_ecc; + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/************************************************************************ +* Name: fts_ctpm_upgrade_idc_init +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_upgrade_idc_init(struct i2c_client *client) +{ + int i_ret = 0; + u8 reg_val_id[4] = {0}; + u8 auc_i2c_write_buf[10]; + + FTS_INFO("[UPGRADE]**********Upgrade setting Init**********"); + + /*read flash ID*/ + auc_i2c_write_buf[0] = 0x05; + reg_val_id[0] = 0x00; + i_ret =fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val_id, 1); + if (i_ret < 0) + { + return -EIO; + } + + /*set flash clk*/ + auc_i2c_write_buf[0] = 0x05; + auc_i2c_write_buf[1] = reg_val_id[0];//0x80; + auc_i2c_write_buf[2] = 0x00; + fts_i2c_write(client, auc_i2c_write_buf, 3); + + /*send upgrade type to reg 0x09: 0x0B: upgrade; 0x0A: download*/ + auc_i2c_write_buf[0] = 0x09; + auc_i2c_write_buf[1] = 0x0B; + fts_i2c_write(client, auc_i2c_write_buf, 2); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_start_pramboot +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +void fts_ctpm_start_pramboot(struct i2c_client *client) +{ + u8 auc_i2c_write_buf[10]; + + FTS_INFO("[UPGRADE]**********start pramboot**********"); + auc_i2c_write_buf[0] = 0x08; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(20); +} + +/************************************************************************ +* Name: fts_ctpm_start_fw_upgrade +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_start_fw_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + + /*send the soft upgrade commond to FW, and start upgrade*/ + FTS_INFO("[UPGRADE]**********send 0xAA and 0x55 to FW, start upgrade**********"); + + i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA); + msleep(10); + i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55); + msleep(200); + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_check_run_state +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +bool fts_ctpm_check_run_state(struct i2c_client *client, int rstate) +{ + int i = 0; + enum FW_STATUS cstate = FTS_RUN_IN_ERROR; + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) + { + cstate = fts_ctpm_get_pram_or_rom_id(client); + FTS_DEBUG( "[UPGRADE]: run state = %d", cstate); + + if (cstate == rstate) + return true; + msleep(20); + } + + return false; +} + +/************************************************************************ +* Name: fts_ctpm_pramboot_ecc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_pramboot_ecc(struct i2c_client *client) +{ + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_FUNC_ENTER(); + + /*read out checksum, if pramboot checksum != host checksum, upgrade fail*/ + FTS_INFO("[UPGRADE]******read out pramboot checksum******"); + auc_i2c_write_buf[0] = 0xcc; + msleep(2); + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) /*pramboot checksum != host checksum, upgrade fail*/ + { + FTS_ERROR("[UPGRADE]: checksum fail : pramboot_ecc = %X, host_ecc = %X!!",reg_val[0],upgrade_ecc); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: checksum success : pramboot_ecc = %X, host_ecc = %X!!",reg_val[0],upgrade_ecc); + msleep(100); + + FTS_FUNC_EXIT(); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_upgrade_ecc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_upgrade_ecc(struct i2c_client *client, u32 startaddr, u32 length) +{ + u32 i = 0; + u8 auc_i2c_write_buf[10]; + u32 temp; + u8 reg_val[4] = {0}; + int i_ret = 0; + + FTS_INFO( "[UPGRADE]**********read out checksum**********"); + + /*check sum init*/ + auc_i2c_write_buf[0] = 0x64; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(300); + + /*send commond to pramboot to start checksum*/ + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(startaddr >> 16); + auc_i2c_write_buf[2] = (u8)(startaddr >> 8); + auc_i2c_write_buf[3] = (u8)(startaddr); + + if (length > LEN_FLASH_ECC_MAX) + { + temp = LEN_FLASH_ECC_MAX; + } + else + { + temp = length; + } + + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + msleep(length/256); + + /*read status : if check sum is finished?*/ + for (i = 0; i < 100; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0==reg_val[0] && 0x55==reg_val[1]) + { + break; + } + msleep(1); + + } + + if (length > LEN_FLASH_ECC_MAX) + { + temp = LEN_FLASH_ECC_MAX; + auc_i2c_write_buf[0] = 0x65; + auc_i2c_write_buf[1] = (u8)(temp >> 16); + auc_i2c_write_buf[2] = (u8)(temp >> 8); + auc_i2c_write_buf[3] = (u8)(temp); + temp = length-LEN_FLASH_ECC_MAX; + auc_i2c_write_buf[4] = (u8)(temp >> 8); + auc_i2c_write_buf[5] = (u8)(temp); + i_ret = fts_i2c_write(client, auc_i2c_write_buf, 6); + + msleep(length/256); + + for (i = 0; i < 100; i++) + { + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0==reg_val[0] && 0x55==reg_val[1]) + { + break; + } + msleep(1); + } + } + + /*read out check sum*/ + auc_i2c_write_buf[0] = 0x66; + i_ret = fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != upgrade_ecc) /*if check sum fail, upgrade fail*/ + { + FTS_ERROR( "[UPGRADE]: ecc error! FW=%02x upgrade_ecc=%02x!!", reg_val[0], upgrade_ecc); + return -EIO; + } + + FTS_DEBUG( "[UPGRADE]: ecc success : FW=%02x upgrade_ecc=%02x!!", reg_val[0], upgrade_ecc); + + upgrade_ecc = 0; + + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_erase_flash +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_erase_flash(struct i2c_client *client) +{ + u32 i = 0; + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_INFO("[UPGRADE]**********erase app now**********"); + + /*send to erase flash*/ + auc_i2c_write_buf[0] = 0x61; + fts_i2c_write(client, auc_i2c_write_buf, 1); + msleep(1350); + + for (i = 0; i < 15; i++) + { + /*get the erase app status, if get 0xF0AA٬erase flash success*/ + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if (0xF0==reg_val[0] && 0xAA==reg_val[1]) /*erase flash success*/ + { + break; + } + msleep(50); + } + + if ((0xF0!=reg_val[0] || 0xAA!=reg_val[1]) && (i >= 15)) /*erase flash fail*/ + { + FTS_ERROR("[UPGRADE]: erase app error.reset tp and reload FW!!"); + return -EIO; + } + FTS_DEBUG("[UPGRADE]: erase app ok!!"); + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_pramboot_for_idc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client, u32 length, u8 *readbuf) +{ + u32 i = 0; + u32 j; + u32 temp; + u32 packet_number; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + + upgrade_ecc = 0; + FTS_INFO("[UPGRADE]**********write pramboot to pram**********"); + + temp = 0; + packet_number = (length) / FTS_PACKET_LENGTH; + if ((length) % FTS_PACKET_LENGTH > 0) + { + packet_number++; + } + packet_buf[0] = 0xae; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) + { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + if (j < (packet_number-1)) + { + temp = FTS_PACKET_LENGTH; + } + else + { + temp = (length) % FTS_PACKET_LENGTH; + } + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) + { + packet_buf[6 + i] = readbuf[j * FTS_PACKET_LENGTH + i]; + upgrade_ecc ^= packet_buf[6 + i]; + } + fts_i2c_write(client, packet_buf, temp + 6); + } + + return 0; +} + +/************************************************************************ +* Name: fts_ctpm_write_app_for_idc +* Brief: +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_ctpm_write_app_for_idc(struct i2c_client *client, u32 length, u8 *readbuf) +{ + u32 j; + u32 i = 0; + u32 packet_number; + u32 temp; + u32 writelenght; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 reg_val[4] = {0}; + + FTS_INFO( "[UPGRADE]**********write app to flash**********"); + + upgrade_ecc = 0; + + packet_number = (length) / FTS_PACKET_LENGTH; + if (((length) % FTS_PACKET_LENGTH) > 0) + { + packet_number++; + } + + packet_buf[0] = 0xbf; + + for (j = 0; j < packet_number; j++) + { + temp = 0x1000+j * FTS_PACKET_LENGTH; + + if (j<(packet_number-1)) + { + writelenght = FTS_PACKET_LENGTH; + } + else + { + writelenght = ((length) % FTS_PACKET_LENGTH); + } + packet_buf[1] = (u8) (temp >> 16); + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + packet_buf[4] = (u8) (writelenght >> 8); + packet_buf[5] = (u8) writelenght; + + for (i = 0; i < writelenght; i++) + { + packet_buf[6 + i] = readbuf[(temp - 0x1000+i)]; + upgrade_ecc ^= packet_buf[6 + i]; + } + + fts_i2c_write(client, packet_buf, (writelenght + 6)); + + for (i = 0; i < 30; i++) + { + /*read status and check if the app writting is finished*/ + auc_i2c_write_buf[0] = 0x6a; + reg_val[0] = reg_val[1] = 0x00; + fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 2); + + if ((j + 0x20+0x1000) == (((reg_val[0]) << 8) | reg_val[1])) + { + break; + } + //msleep(1); + fts_ctpm_upgrade_delay(1000); + } + } + msleep(50); + + return 0; +} +#endif /* IDC */ diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c new file mode 100755 index 000000000000..05115683d1ff --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_flash/focaltech_upgrade_test.c @@ -0,0 +1,179 @@ +/* + * + * FocalTech fts TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_upgrade_test.c +* +* Author: fupeipei +* +* Created: 2016-08-22 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "../focaltech_core.h" +#include "../focaltech_flash.h" +//#include +#include + +/***************************************************************************** +* Static variables +*****************************************************************************/ +#define FTS_GET_UPGRADE_TIME 0 + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ +//struct wake_lock ps_lock; + +#define FTS_DEBUG_UPGRADE(fmt, args...) do{\ + printk(KERN_ERR "[FTS][UPGRADE]:##############################################################################\n");\ + printk(KERN_ERR "[FTS][UPGRADE]: "fmt"\n", ##args);\ + printk(KERN_ERR "[FTS][UPGRADE]:##############################################################################\n");\ + }while(0)\ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +#if (FTS_UPGRADE_STRESS_TEST) +/************************************************************************ +* Name: fts_ctpm_auto_upgrade_pingpong +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +static int fts_ctpm_auto_upgrade_pingpong(struct i2c_client *client) +{ + u8 uc_tp_fm_ver; + int i_ret = 0; + u8 uc_upgrade_times = 0; + + FTS_FUNC_ENTER(); + + /* pingpong test mode, need upgrade */ + FTS_INFO("[UPGRADE]: pingpong test mode, need upgrade!!"); + do + { + uc_upgrade_times++; + + /* fw upgrade */ + i_ret = fts_ctpm_fw_upgrade(client); + + if (i_ret == 0) /* upgrade success */ + { + fts_i2c_read_reg(client, FTS_REG_FW_VER, &uc_tp_fm_ver); + FTS_DEBUG("[UPGRADE]: upgrade to new version 0x%x", uc_tp_fm_ver); + } + else /* upgrade fail */ + { + /* if upgrade fail, reset to run ROM. if app in flash is ok. TP will work success */ + FTS_INFO("[UPGRADE]: upgrade fail, reset now!!"); + fts_ctpm_rom_or_pram_reset(client); + } + } + while ((i_ret != 0) && (uc_upgrade_times < 2)); /* if upgrade fail, upgrade again. then return */ + + FTS_FUNC_EXIT(); + return i_ret; +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +void fts_ctpm_display_upgrade_time(bool start_time) +{ +#if FTS_GET_UPGRADE_TIME + static struct timeval tpend; + static struct timeval tpstart; + static int timeuse; + + if (start_time) + { + do_gettimeofday(&tpstart); + } + else + { + do_gettimeofday(&tpend); + timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+ tpend.tv_usec-tpstart.tv_usec; + timeuse/=1000000; + FTS_DEBUG( "[UPGRADE]: upgrade success : Use time: %d Seconds!!", timeuse); + } +#endif +} + +/************************************************************************ +* Name: fts_ctpm_auto_upgrade +* Brief: 0 +* Input: 0 +* Output: 0 +* Return: 0 +***********************************************************************/ +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + int i_ret = 0; + static int uc_ErrorTimes = 0; + static int uc_UpgradeTimes = 0; + + // wake_lock_init(&ps_lock, WAKE_LOCK_SUSPEND, "tp_wakelock"); + + // wake_lock(&ps_lock); + + /* (FTS_GET_VENDOR_ID_NUM == 0) */ + g_fw_file = CTPM_FW; + g_fw_len = fts_getsize(FW_SIZE); + FTS_DEBUG("[UPGRADE]FW FILE:CTPM_FW, SIZE:%x", g_fw_len); + + do + { + uc_UpgradeTimes++; + + FTS_DEBUG_UPGRADE("start to upgrade %d times !!", uc_UpgradeTimes); + + fts_ctpm_display_upgrade_time(true); + + i_ret = fts_ctpm_auto_upgrade_pingpong(client); + if (i_ret == 0) + { + fts_ctpm_display_upgrade_time(false); + } + else + { + uc_ErrorTimes++; + } + + FTS_DEBUG_UPGRADE("upgrade %d times, error %d times!!", uc_UpgradeTimes, uc_ErrorTimes); + } + while (uc_UpgradeTimes < (FTS_UPGRADE_TEST_NUMBER)); + + // wake_unlock(&ps_lock); + + return 0; +} +#endif + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_gesture.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_gesture.c new file mode 100755 index 000000000000..b1c690e9676e --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_gesture.c @@ -0,0 +1,670 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, Focaltech Ltd. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/***************************************************************************** +* +* File Name: focaltech_gestrue.c +* +* Author: Focaltech Driver Team +* +* Created: 2016-08-08 +* +* Abstract: +* +* Reference: +* +*****************************************************************************/ + +/***************************************************************************** +* 1.Included header files +*****************************************************************************/ +#include "focaltech_core.h" +#if FTS_GESTURE_EN +/****************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +#define KEY_GESTURE_U KEY_U +#define KEY_GESTURE_UP KEY_UP +#define KEY_GESTURE_DOWN KEY_DOWN +#define KEY_GESTURE_LEFT KEY_LEFT +#define KEY_GESTURE_RIGHT KEY_RIGHT +#define KEY_GESTURE_O KEY_O +#define KEY_GESTURE_E KEY_E +#define KEY_GESTURE_M KEY_M +#define KEY_GESTURE_L KEY_L +#define KEY_GESTURE_W KEY_W +#define KEY_GESTURE_S KEY_S +#define KEY_GESTURE_V KEY_V +#define KEY_GESTURE_C KEY_C +#define KEY_GESTURE_Z KEY_Z + +#define GESTURE_LEFT 0x20 +#define GESTURE_RIGHT 0x21 +#define GESTURE_UP 0x22 +#define GESTURE_DOWN 0x23 +#define GESTURE_DOUBLECLICK 0x24 +#define GESTURE_O 0x30 +#define GESTURE_W 0x31 +#define GESTURE_M 0x32 +#define GESTURE_E 0x33 +#define GESTURE_L 0x44 +#define GESTURE_S 0x46 +#define GESTURE_V 0x54 +#define GESTURE_Z 0x41 +#define GESTURE_C 0x34 +#define FTS_GESTRUE_POINTS 255 +#define FTS_GESTRUE_POINTS_HEADER 8 + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ +/* +* header - byte0:gesture id +* byte1:pointnum +* byte2~7:reserved +* coordinate_x - All gesture point x coordinate +* coordinate_y - All gesture point y coordinate +* mode - 1:enable gesture function(default) +* - 0:disable +* active - 1:enter into gesture(suspend) +* 0:gesture disable or resume +*/ +struct fts_gesture_st +{ + u8 header[FTS_GESTRUE_POINTS_HEADER]; + u16 coordinate_x[FTS_GESTRUE_POINTS]; + u16 coordinate_y[FTS_GESTRUE_POINTS]; + u8 mode; + u8 active; +}; + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct fts_gesture_st fts_gesture_data; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ +static ssize_t fts_gesture_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t fts_gesture_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +static ssize_t fts_gesture_buf_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t fts_gesture_buf_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); + +/* sysfs gesture node + * read example: cat fts_gesture_mode ---read gesture mode + * write example:echo 01 > fts_gesture_mode ---write gesture mode to 01 + * + */ +static DEVICE_ATTR (fts_gesture_mode, S_IRUGO|S_IWUSR, fts_gesture_show, fts_gesture_store); +/* + * read example: cat fts_gesture_buf ---read gesture buf + */ +static DEVICE_ATTR (fts_gesture_buf, S_IRUGO|S_IWUSR, fts_gesture_buf_show, fts_gesture_buf_store); +static struct attribute *fts_gesture_mode_attrs[] = +{ + + &dev_attr_fts_gesture_mode.attr, + &dev_attr_fts_gesture_buf.attr, + NULL, +}; + +static struct attribute_group fts_gesture_group = +{ + .attrs = fts_gesture_mode_attrs, +}; + +/************************************************************************ +* Name: fts_gesture_show +* Brief: +* Input: device, device attribute, char buf +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + u8 val; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&fts_input_dev->mutex); + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &val); + count = sprintf(buf, "Gesture Mode: %s\n", fts_gesture_data.mode ? "On" : "Off"); + count += sprintf(buf + count, "Reg(0xD0) = %d\n", val); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_store +* Brief: +* Input: device, device attribute, char buf, char count +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + mutex_lock(&fts_input_dev->mutex); + + if (FTS_SYSFS_ECHO_ON(buf)) + { + FTS_INFO("[GESTURE]enable gesture"); + fts_gesture_data.mode = ENABLE; + } + else if (FTS_SYSFS_ECHO_OFF(buf)) + { + FTS_INFO("[GESTURE]disable gesture"); + fts_gesture_data.mode = DISABLE; + } + + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_buf_show +* Brief: +* Input: device, device attribute, char buf +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_buf_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int count; + int i = 0; + + mutex_lock(&fts_input_dev->mutex); + count = snprintf(buf, PAGE_SIZE, "Gesture ID: 0x%x\n", fts_gesture_data.header[0]); + count += snprintf(buf + count, PAGE_SIZE, "Gesture PointNum: %d\n", fts_gesture_data.header[1]); + count += snprintf(buf + count, PAGE_SIZE, "Gesture Point Buf:\n"); + for (i = 0; i < fts_gesture_data.header[1]; i++) + { + count += snprintf(buf + count, PAGE_SIZE, "%3d(%4d,%4d) ", i, fts_gesture_data.coordinate_x[i], fts_gesture_data.coordinate_y[i]); + if ((i + 1)%4 == 0) + count += snprintf(buf + count, PAGE_SIZE, "\n"); + } + count += snprintf(buf + count, PAGE_SIZE, "\n"); + mutex_unlock(&fts_input_dev->mutex); + + return count; +} + +/************************************************************************ +* Name: fts_gesture_buf_store +* Brief: +* Input: device, device attribute, char buf, char count +* Output: +* Return: +***********************************************************************/ +static ssize_t fts_gesture_buf_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + /* place holder for future use */ + return -EPERM; +} + +/***************************************************************************** +* Name: fts_create_gesture_sysfs +* Brief: +* Input: +* Output: +* Return: 0-success or others-error +*****************************************************************************/ +int fts_create_gesture_sysfs(struct i2c_client *client) +{ + int ret = 0; + + ret = sysfs_create_group(&client->dev.kobj, &fts_gesture_group); + if ( ret != 0) + { + FTS_ERROR( "[GESTURE]fts_gesture_mode_group(sysfs) create failed!"); + sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); + return ret; + } + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_report +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_gesture_report(struct input_dev *input_dev,int gesture_id) +{ + int gesture; + + FTS_FUNC_ENTER(); + FTS_DEBUG("fts gesture_id==0x%x ",gesture_id); + switch (gesture_id) + { + case GESTURE_LEFT: + gesture = KEY_GESTURE_LEFT; + break; + case GESTURE_RIGHT: + gesture = KEY_GESTURE_RIGHT; + break; + case GESTURE_UP: + gesture = KEY_GESTURE_UP; + break; + case GESTURE_DOWN: + gesture = KEY_GESTURE_DOWN; + break; + case GESTURE_DOUBLECLICK: + gesture = KEY_GESTURE_U; + break; + case GESTURE_O: + gesture = KEY_GESTURE_O; + break; + case GESTURE_W: + gesture = KEY_GESTURE_W; + break; + case GESTURE_M: + gesture = KEY_GESTURE_M; + break; + case GESTURE_E: + gesture = KEY_GESTURE_E; + break; + case GESTURE_L: + gesture = KEY_GESTURE_L; + break; + case GESTURE_S: + gesture = KEY_GESTURE_S; + break; + case GESTURE_V: + gesture = KEY_GESTURE_V; + break; + case GESTURE_Z: + gesture = KEY_GESTURE_Z; + break; + case GESTURE_C: + gesture = KEY_GESTURE_C; + break; + default: + gesture = -1; + break; + } + /* report event key */ + if (gesture != -1) + { + FTS_DEBUG("Gesture Code=%d", gesture); + input_report_key(input_dev, gesture, 1); + input_sync(input_dev); + input_report_key(input_dev, gesture, 0); + input_sync(input_dev); + } + + FTS_FUNC_EXIT(); +} + +/************************************************************************ +* Name: fts_gesture_readdata +* Brief: read data from TP register +* Input: +* Output: +* Return: fail <0 +***********************************************************************/ +static int fts_gesture_read_buffer(struct i2c_client *client, u8 *buf, int read_bytes) +{ + int remain_bytes; + int ret; + int i; + + if (read_bytes <= I2C_BUFFER_LENGTH_MAXINUM) + { + ret = fts_i2c_read(client, buf, 1, buf, read_bytes); + } + else + { + ret = fts_i2c_read(client, buf, 1, buf, I2C_BUFFER_LENGTH_MAXINUM); + remain_bytes = read_bytes - I2C_BUFFER_LENGTH_MAXINUM; + for (i = 1; remain_bytes > 0; i++) + { + if (remain_bytes <= I2C_BUFFER_LENGTH_MAXINUM) + ret = fts_i2c_read(client, buf, 0, buf + I2C_BUFFER_LENGTH_MAXINUM * i, remain_bytes); + else + ret = fts_i2c_read(client, buf, 0, buf + I2C_BUFFER_LENGTH_MAXINUM * i, I2C_BUFFER_LENGTH_MAXINUM); + remain_bytes -= I2C_BUFFER_LENGTH_MAXINUM; + } + } + + return ret; +} + +/************************************************************************ +* Name: fts_gesture_fw +* Brief: Check IC's gesture recognise by FW or not +* Input: +* Output: +* Return: 1- FW 0- Driver +***********************************************************************/ +static int fts_gesture_fw(void) +{ + int ret = 0; + + switch (chip_types.chip_idh) + { + case 0x54: + case 0x58: + case 0x64: + case 0x87: + case 0x86: + case 0x80: + case 0xE7: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +/************************************************************************ +* Name: fts_gesture_readdata +* Brief: read data from TP register +* Input: +* Output: +* Return: fail <0 +***********************************************************************/ +int fts_gesture_readdata(struct i2c_client *client) +{ + u8 buf[FTS_GESTRUE_POINTS * 4] = { 0 }; + int ret = -1; + int i = 0; + int gestrue_id = 0; + int read_bytes = 0; + u8 pointnum; + + FTS_FUNC_ENTER(); + /* init variable before read gesture point */ + memset(fts_gesture_data.header, 0, FTS_GESTRUE_POINTS_HEADER); + memset(fts_gesture_data.coordinate_x, 0, FTS_GESTRUE_POINTS * sizeof(u16)); + memset(fts_gesture_data.coordinate_y, 0, FTS_GESTRUE_POINTS * sizeof(u16)); + + buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + ret = fts_i2c_read(client, buf, 1, buf, FTS_GESTRUE_POINTS_HEADER); + if (ret < 0) + { + FTS_ERROR("[GESTURE]Read gesture header data failed!!"); + FTS_FUNC_EXIT(); + return ret; + } + + /* FW recognize gesture */ + if (fts_gesture_fw()) + { + memcpy(fts_gesture_data.header, buf, FTS_GESTRUE_POINTS_HEADER); + gestrue_id = buf[0]; + pointnum = buf[1]; + read_bytes = ((int)pointnum) * 4 + 2; + buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + FTS_DEBUG("[GESTURE]PointNum=%d", pointnum); + ret = fts_gesture_read_buffer(client, buf, read_bytes); + if (ret < 0) + { + FTS_ERROR("[GESTURE]Read gesture touch data failed!!"); + FTS_FUNC_EXIT(); + return ret; + } + + fts_gesture_report(fts_input_dev,gestrue_id); + for (i = 0; i < pointnum; i++) + { + fts_gesture_data.coordinate_x[i] = (((s16) buf[0 + (4 * i + 2)]) & 0x0F) << 8 + | (((s16) buf[1 + (4 * i + 2)]) & 0xFF); + fts_gesture_data.coordinate_y[i] = (((s16) buf[2 + (4 * i + 2)]) & 0x0F) << 8 + | (((s16) buf[3 + (4 * i + 2)]) & 0xFF); + } + FTS_FUNC_EXIT(); + return 0; + } + else + { + FTS_ERROR("[GESTURE]IC 0x%x need gesture lib to support gestures.", chip_types.chip_idh); + return 0; + } +#if 0 + /* other IC's gestrue in driver, need gesture library */ + if (0x24 == buf[0]) + { + gestrue_id = 0x24; + fts_gesture_report(fts_input_dev, gestrue_id); + FTS_DEBUG("[GESTURE]%d check_gesture gestrue_id", gestrue_id); + FTS_FUNC_EXIT(); + return -1; + } + + /* Host Driver recognize gesture */ + pointnum = buf[1]; + read_bytes = ((int)pointnum) * 4 + 2; + buf[0] = FTS_REG_GESTURE_OUTPUT_ADDRESS; + ret = fts_gesture_read_buffer(client, buf, read_bytes); + if (ret < 0) + { + FTS_ERROR("[GESTURE]Driver recognize gesture - Read gesture touch data failed!!"); + FTS_FUNC_EXIT(); + return ret; + } + + /* + * Host Driver recognize gesture, need gesture lib.a + * Not use now for compatibility + */ + gestrue_id = fetch_object_sample(buf, pointnum); + fts_gesture_report(fts_input_dev, gestrue_id); + FTS_DEBUG("[GESTURE]%d read gestrue_id", gestrue_id); + + for (i = 0; i < pointnum; i++) + { + fts_gesture_data.coordinate_x[i] = (((s16) buf[0 + (4 * i+8)]) & 0x0F) << 8 + | (((s16) buf[1 + (4 * i+8)])& 0xFF); + fts_gesture_data.coordinate_y[i] = (((s16) buf[2 + (4 * i+8)]) & 0x0F) << 8 + | (((s16) buf[3 + (4 * i+8)]) & 0xFF); + } + FTS_FUNC_EXIT(); + return -1; +#endif +} + +/***************************************************************************** +* Name: fts_gesture_recovery +* Brief: recovery gesture state when reset or power on +* Input: +* Output: +* Return: +*****************************************************************************/ +void fts_gesture_recovery(struct i2c_client *client) +{ + if (fts_gesture_data.mode && fts_gesture_data.active) + { + fts_i2c_write_reg(client, 0xD1, 0xff); + fts_i2c_write_reg(client, 0xD2, 0xff); + fts_i2c_write_reg(client, 0xD5, 0xff); + fts_i2c_write_reg(client, 0xD6, 0xff); + fts_i2c_write_reg(client, 0xD7, 0xff); + fts_i2c_write_reg(client, 0xD8, 0xff); + fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, ENABLE); + } +} + +/***************************************************************************** +* Name: fts_gesture_suspend +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_suspend(struct i2c_client *i2c_client) +{ + int i; + u8 state; + + FTS_FUNC_ENTER(); + + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == 0) + { + FTS_DEBUG("gesture is disabled"); + FTS_FUNC_EXIT(); + return -1; + } + + for (i = 0; i < 5; i++) + { + fts_i2c_write_reg(i2c_client, 0xd1, 0xff); + fts_i2c_write_reg(i2c_client, 0xd2, 0xff); + fts_i2c_write_reg(i2c_client, 0xd5, 0xff); + fts_i2c_write_reg(i2c_client, 0xd6, 0xff); + fts_i2c_write_reg(i2c_client, 0xd7, 0xff); + fts_i2c_write_reg(i2c_client, 0xd8, 0xff); + fts_i2c_write_reg(i2c_client, FTS_REG_GESTURE_EN, 0x01); + msleep(1); + fts_i2c_read_reg(i2c_client, FTS_REG_GESTURE_EN, &state); + if (state == 1) + break; + } + + if (i >= 5) + { + FTS_ERROR("[GESTURE]Enter into gesture(suspend) failed!\n"); + FTS_FUNC_EXIT(); + return -1; + } + + fts_gesture_data.active = 1; + FTS_DEBUG("[GESTURE]Enter into gesture(suspend) successfully!"); + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_resume +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_resume(struct i2c_client *client) +{ + int i; + u8 state; + FTS_FUNC_ENTER(); + + /* gesture not enable, return immediately */ + if (fts_gesture_data.mode == 0) + { + FTS_DEBUG("gesture is disabled"); + FTS_FUNC_EXIT(); + return -1; + } + + if (fts_gesture_data.active == 0) + { + FTS_DEBUG("gesture is unactive"); + FTS_FUNC_EXIT(); + return -1; + } + + fts_gesture_data.active = 0; + for (i = 0; i < 5; i++) + { + fts_i2c_write_reg(client, FTS_REG_GESTURE_EN, 0x00); + msleep(1); + fts_i2c_read_reg(client, FTS_REG_GESTURE_EN, &state); + if (state == 0) + break; + } + + if (i >= 5) + { + FTS_ERROR("[GESTURE]Clear gesture(resume) failed!\n"); + } + + FTS_FUNC_EXIT(); + return 0; +} + +/***************************************************************************** +* Name: fts_gesture_init +* Brief: +* Input: +* Output: None +* Return: None +*****************************************************************************/ +int fts_gesture_init(struct input_dev *input_dev, struct i2c_client *client) +{ + FTS_FUNC_ENTER(); + input_set_capability(input_dev, EV_KEY, KEY_POWER); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z); + input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C); + + __set_bit(KEY_GESTURE_RIGHT, input_dev->keybit); + __set_bit(KEY_GESTURE_LEFT, input_dev->keybit); + __set_bit(KEY_GESTURE_UP, input_dev->keybit); + __set_bit(KEY_GESTURE_DOWN, input_dev->keybit); + __set_bit(KEY_GESTURE_U, input_dev->keybit); + __set_bit(KEY_GESTURE_O, input_dev->keybit); + __set_bit(KEY_GESTURE_E, input_dev->keybit); + __set_bit(KEY_GESTURE_M, input_dev->keybit); + __set_bit(KEY_GESTURE_W, input_dev->keybit); + __set_bit(KEY_GESTURE_L, input_dev->keybit); + __set_bit(KEY_GESTURE_S, input_dev->keybit); + __set_bit(KEY_GESTURE_V, input_dev->keybit); + __set_bit(KEY_GESTURE_C, input_dev->keybit); + __set_bit(KEY_GESTURE_Z, input_dev->keybit); + + fts_create_gesture_sysfs(client); + fts_gesture_data.mode = 1; + fts_gesture_data.active = 0; + FTS_FUNC_EXIT(); + return 0; +} + +/************************************************************************ +* Name: fts_gesture_exit +* Brief: call when driver removed +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_gesture_exit(struct i2c_client *client) +{ + FTS_FUNC_ENTER(); + sysfs_remove_group(&client->dev.kobj, &fts_gesture_group); + FTS_FUNC_EXIT(); + return 0; +} +#endif diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_i2c.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_i2c.c new file mode 100755 index 000000000000..9e56edb03171 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_i2c.c @@ -0,0 +1,216 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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: fupeipei +* +* Created: 2016-08-04 +* +* Abstract: i2c communication with TP +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By fupeipei 2016-08-04 +************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static DEFINE_MUTEX(i2c_rw_access); + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ + +/************************************************************************ +* Name: fts_i2c_read +* Brief: i2c read +* Input: i2c info, write buf, write len, read buf, read len +* Output: get data in the 3rd buf +* Return: fail <0 +***********************************************************************/ +int fts_i2c_read(struct i2c_client *client, char *writebuf,int writelen, char *readbuf, int readlen) +{ + int ret = 0; + + mutex_lock(&i2c_rw_access); + + if (readlen > 0) + { + if (writelen > 0) + { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + { + FTS_ERROR("[IIC]: i2c_transfer(write) error, ret=%d!!", ret); + } + } + else + { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + { + FTS_ERROR("[IIC]: i2c_transfer(read) error, ret=%d!!", ret); + } + } + } + + mutex_unlock(&i2c_rw_access); + return ret; +} + +/************************************************************************ +* Name: fts_i2c_write +* Brief: i2c write +* Input: i2c info, write buf, write len +* Output: no +* Return: fail <0 +***********************************************************************/ +int fts_i2c_write(struct i2c_client *client, char *writebuf, int writelen) +{ + int ret = 0; + + mutex_lock(&i2c_rw_access); + if (writelen > 0) + { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + { + FTS_ERROR("%s: i2c_transfer(write) error, ret=%d", __func__, ret); + } + } + mutex_unlock(&i2c_rw_access); + + return ret; +} + +/************************************************************************ +* Name: fts_i2c_write_reg +* Brief: write register +* Input: i2c info, reg address, reg value +* Output: no +* Return: fail <0 +***********************************************************************/ +int fts_i2c_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) +{ + u8 buf[2] = {0}; + + buf[0] = regaddr; + buf[1] = regvalue; + return fts_i2c_write(client, buf, sizeof(buf)); +} + +/************************************************************************ +* Name: fts_i2c_read_reg +* Brief: read register +* Input: i2c info, reg address, reg value +* Output: get reg value +* Return: fail <0 +***********************************************************************/ +int fts_i2c_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) +{ + return fts_i2c_read(client, ®addr, 1, regvalue, 1); +} + +/************************************************************************ +* Name: fts_i2c_init +* Brief: fts i2c init +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_i2c_init(void) +{ + FTS_FUNC_ENTER(); + + FTS_FUNC_EXIT(); + return 0; +} +/************************************************************************ +* Name: fts_i2c_exit +* Brief: fts i2c exit +* Input: +* Output: +* Return: +***********************************************************************/ +int fts_i2c_exit(void) +{ + FTS_FUNC_ENTER(); + + FTS_FUNC_EXIT(); + return 0; +} + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_point_report_check.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_point_report_check.c new file mode 100755 index 000000000000..9d1cf2c4cd1f --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_point_report_check.c @@ -0,0 +1,153 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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: WangTao +* +* Created: 2016-11-16 +* +* Abstract: point report check function +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By WangTao 2016-11-16 +*****************************************************************************/ + +/***************************************************************************** +* 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 //ms + +/***************************************************************************** +* Private enumerations, structures and unions using typedef +*****************************************************************************/ + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct delayed_work fts_point_report_check_work; +static struct workqueue_struct *fts_point_report_check_workqueue = NULL; + +/***************************************************************************** +* Global variable or extern global variabls/functions +*****************************************************************************/ + +/***************************************************************************** +* Static function prototypes +*****************************************************************************/ + +/***************************************************************************** +* functions body +*****************************************************************************/ + + +/***************************************************************************** +* Name: fts_point_report_check_func +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_point_report_check_func(struct work_struct *work) +{ + +#if FTS_MT_PROTOCOL_B_EN + unsigned int finger_count=0; +#endif + + FTS_FUNC_ENTER(); + mutex_lock(&fts_wq_data->report_mutex); + +#if FTS_MT_PROTOCOL_B_EN + for (finger_count = 0; finger_count < fts_wq_data->pdata->max_touch_number; finger_count++) + { + input_mt_slot(fts_input_dev, finger_count); + input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER, false); + } +#else + input_mt_sync(fts_input_dev); +#endif + input_report_key(fts_input_dev, BTN_TOUCH, 0); + input_sync(fts_input_dev); + + mutex_unlock(&fts_wq_data->report_mutex); + + FTS_FUNC_EXIT(); +} + +void fts_point_report_check_queue_work(void) +{ + cancel_delayed_work(&fts_point_report_check_work); + queue_delayed_work(fts_point_report_check_workqueue, &fts_point_report_check_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(void) +{ + FTS_FUNC_ENTER(); + + INIT_DELAYED_WORK(&fts_point_report_check_work, fts_point_report_check_func); + fts_point_report_check_workqueue = create_workqueue("fts_point_report_check_func_wq"); + if (fts_point_report_check_workqueue == NULL) + { + FTS_ERROR("[POINT_REPORT]: Failed to create fts_point_report_check_workqueue!!"); + } + else + { + FTS_DEBUG("[POINT_REPORT]: Success to create fts_point_report_check_workqueue!!"); + } + + FTS_FUNC_EXIT(); + + return 0; +} + +/***************************************************************************** +* Name: fts_point_report_check_exit +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +int fts_point_report_check_exit(void) +{ + FTS_FUNC_ENTER(); + + destroy_workqueue(fts_point_report_check_workqueue); + + FTS_FUNC_EXIT(); + return 0; +} +#endif /* FTS_POINT_REPORT_CHECK_EN */ + diff --git a/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_sensor.c b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_sensor.c new file mode 100755 index 000000000000..35e0d9ea4673 --- /dev/null +++ b/drivers/amlogic/input/touchscreen/focaltech_touch/focaltech_sensor.c @@ -0,0 +1,329 @@ +/* + * + * FocalTech TouchScreen driver. + * + * Copyright (c) 2010-2017, 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: Sensor +* +* Version: v1.0 +* +* Revision History: +* v1.0: +* First release. By luougojin 2016-08-03 +*****************************************************************************/ + +/***************************************************************************** +* Included header files +*****************************************************************************/ +#include "focaltech_core.h" + +#if FTS_PSENSOR_EN +/***************************************************************************** +* Private constant and macro definitions using #define +*****************************************************************************/ +/* psensor register address*/ +#define FTS_REG_PSENSOR_ENABLE 0xB0 +#define FTS_REG_PSENSOR_STATUS 0x01 + +/* psensor register bits*/ +#define FTS_PSENSOR_ENABLE_MASK 0x01 +#define FTS_PSENSOR_STATUS_NEAR 0xC0 +#define FTS_PSENSOR_STATUS_FAR 0xE0 +#define FTS_PSENSOR_FAR_TO_NEAR 0 +#define FTS_PSENSOR_NEAR_TO_FAR 1 +#define FTS_PSENSOR_ORIGINAL_STATE_FAR 1 +#define FTS_PSENSOR_WAKEUP_TIMEOUT 500 + +/***************************************************************************** +* Static variables +*****************************************************************************/ +static struct sensors_classdev __maybe_unused sensors_proximity_cdev = +{ + .name = "fts-proximity", + .vendor = "FocalTech", + .version = 1, + .handle = SENSORS_PROXIMITY_HANDLE, + .type = SENSOR_TYPE_PROXIMITY, + .max_range = "5.0", + .resolution = "5.0", + .sensor_power = "0.1", + .min_delay = 0, + .fifo_reserved_event_count = 0, + .fifo_max_event_count = 0, + .enabled = 0, + .delay_msec = 200, + .sensors_enable = NULL, + .sensors_poll_delay = NULL, +}; + +/***************************************************************************** +* functions body +*****************************************************************************/ +/***************************************************************************** +* Name: fts_psensor_support_enabled +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static inline bool fts_psensor_support_enabled(void) +{ + /*return config_enabled(CONFIG_TOUCHSCREEN_FTS_PSENSOR);*/ + return FTS_PSENSOR_EN; +} + +/***************************************************************************** +* Name: fts_psensor_enable +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static void fts_psensor_enable(struct fts_ts_data *data, int enable) +{ + u8 state; + int ret = -1; + + if (data->client == NULL) + return; + + fts_i2c_read_reg(data->client, FTS_REG_PSENSOR_ENABLE, &state); + if (enable) + state |= FTS_PSENSOR_ENABLE_MASK; + else + state &= ~FTS_PSENSOR_ENABLE_MASK; + + ret = fts_i2c_write_reg(data->client, FTS_REG_PSENSOR_ENABLE, state); + if (ret < 0) + FTS_ERROR("write psensor switch command failed"); + return; +} + +/***************************************************************************** +* Name: fts_psensor_enable_set +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_psensor_enable_set(struct sensors_classdev *sensors_cdev, + unsigned int enable) +{ + struct fts_psensor_platform_data *psensor_pdata = + container_of(sensors_cdev, + struct fts_psensor_platform_data, ps_cdev); + struct fts_ts_data *data = psensor_pdata->data; + struct input_dev *input_dev = data->psensor_pdata->input_psensor_dev; + + mutex_lock(&input_dev->mutex); + fts_psensor_enable(data, enable); + psensor_pdata->tp_psensor_data = FTS_PSENSOR_ORIGINAL_STATE_FAR; + if (enable) + psensor_pdata->tp_psensor_opened = 1; + else + psensor_pdata->tp_psensor_opened = 0; + mutex_unlock(&input_dev->mutex); + return enable; +} + +/***************************************************************************** +* Name: fts_read_tp_psensor_data +* Brief: +* Input: +* Output: +* Return: +*****************************************************************************/ +static int fts_read_tp_psensor_data(struct fts_ts_data *data) +{ + u8 psensor_status; + char tmp; + int ret = 1; + + fts_i2c_read_reg(data->client, + FTS_REG_PSENSOR_STATUS, &psensor_status); + + tmp = data->psensor_pdata->tp_psensor_data; + if (psensor_status == FTS_PSENSOR_STATUS_NEAR) + data->psensor_pdata->tp_psensor_data = + FTS_PSENSOR_FAR_TO_NEAR; + else if (psensor_status == FTS_PSENSOR_STATUS_FAR) + data->psensor_pdata->tp_psensor_data = + FTS_PSENSOR_NEAR_TO_FAR; + + if (tmp != data->psensor_pdata->tp_psensor_data) + { + FTS_ERROR("%s sensor data changed", __func__); + ret = 0; + } + return ret; +} + + +int fts_sensor_read_data(struct fts_ts_data *data) +{ + int ret = 0; + if (fts_psensor_support_enabled() && data->psensor_pdata->tp_psensor_opened) + { + ret = fts_read_tp_psensor_data(data); + if ( !ret ) + { + if (data->suspended) + { + pm_wakeup_event(&data->client->dev, FTS_PSENSOR_WAKEUP_TIMEOUT); + } + input_report_abs(data->psensor_pdata->input_psensor_dev, + ABS_DISTANCE, + data->psensor_pdata->tp_psensor_data); + input_sync(data->psensor_pdata->input_psensor_dev); + } + return 1; + } + return 0; +} + +int fts_sensor_suspend(struct fts_ts_data *data) +{ + int ret = 0; + + if ( fts_psensor_support_enabled() && + device_may_wakeup(&data->client->dev) && + data->psensor_pdata->tp_psensor_opened ) + { + ret = enable_irq_wake(data->client->irq); + if ( ret != 0 ) + { + FTS_ERROR("%s: set_irq_wake failed", __func__); + } + data->suspended = true; + return 1; + } + + return 0; +} + + +int fts_sensor_resume(struct fts_ts_data *data) +{ + int ret = 0; + + if ( fts_psensor_support_enabled() && + device_may_wakeup(&data->client->dev) && data->psensor_pdata->tp_psensor_opened ) + { + ret = disable_irq_wake(data->client->irq); + if (ret) + { + FTS_ERROR("%s: disable_irq_wake failed", __func__); + } + data->suspended = false; + return 1; + } + + return 0; +} + + +int fts_sensor_init(struct fts_ts_data *data) +{ + struct fts_psensor_platform_data *psensor_pdata; + struct input_dev *psensor_input_dev; + int err; + + if (fts_psensor_support_enabled() ) + { + device_init_wakeup(&data->client->dev, 1); + psensor_pdata = devm_kzalloc(&data->client->dev, + sizeof(struct fts_psensor_platform_data), + GFP_KERNEL); + if (!psensor_pdata) + { + FTS_ERROR("Failed to allocate memory"); + goto irq_free; + } + data->psensor_pdata = psensor_pdata; + + psensor_input_dev = input_allocate_device(); + if (!psensor_input_dev) + { + FTS_ERROR("Failed to allocate device"); + goto free_psensor_pdata; + } + + __set_bit(EV_ABS, psensor_input_dev->evbit); + input_set_abs_params(psensor_input_dev, ABS_DISTANCE, 0, 1, 0, 0); + psensor_input_dev->name = "proximity"; + psensor_input_dev->id.bustype = BUS_I2C; + psensor_input_dev->dev.parent = &data->client->dev; + data->psensor_pdata->input_psensor_dev = psensor_input_dev; + + err = input_register_device(psensor_input_dev); + if (err) + { + FTS_ERROR("Unable to register device, err=%d", err); + goto free_psensor_input_dev; + } + + psensor_pdata->ps_cdev = sensors_proximity_cdev; + psensor_pdata->ps_cdev.sensors_enable = fts_psensor_enable_set; + psensor_pdata->data = data; + + err = sensors_classdev_register(&data->client->dev, &psensor_pdata->ps_cdev); + if (err) + { + goto unregister_psensor_input_device; + } + } + + return 0; +unregister_psensor_input_device: + if (fts_psensor_support_enabled() ) + input_unregister_device(data->psensor_pdata->input_psensor_dev); +free_psensor_input_dev: + if (fts_psensor_support_enabled() ) + input_free_device(data->psensor_pdata->input_psensor_dev); +free_psensor_pdata: + if (fts_psensor_support_enabled() ) + { + devm_kfree(&data->client->dev, psensor_pdata); + data->psensor_pdata = NULL; + } +irq_free: + if (fts_psensor_support_enabled()) + device_init_wakeup(&data->client->dev, 0); + free_irq(data->client->irq, data); + + return 1; +} + +int fts_sensor_remove(struct fts_ts_data *data) +{ + if (fts_psensor_support_enabled() ) + { + device_init_wakeup(&data->client->dev, 0); + sensors_classdev_unregister(&data->psensor_pdata->ps_cdev); + input_unregister_device(data->psensor_pdata->input_psensor_dev); + devm_kfree(&data->client->dev, data->psensor_pdata); + data->psensor_pdata = NULL; + } + return 0; +} +#endif /* FTS_PSENSOR_EN */