dlkm: input: Port focaltech touch driver

Add focaltech driver into dlkm.
- The dependency on CONFIG_TOUCHSCREEN_FOCALTECH*
are removed in the driver
- Add focaltech,fw-update-mmi in dts for moto firmware update
process
- Changes related to resource release to prevent kernel panic

Change-Id: Ib38c51969e58f827e2996de1a0550bade39036e7
Signed-off-by: wengjun1 <wengjun1@motorola.com>
Reviewed-on: https://gerrit.mot.com/1200328
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Tested-by: Jira Key
Reviewed-by: Hujun Liao <liaohj@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
wengjun1 2018-06-27 17:09:49 +08:00 • committed by Jun Weng
commit 5b22dd7178
12 changed files with 8615 additions and 0 deletions

View file

@ -0,0 +1,8 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := focaltech_mmi.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -0,0 +1,12 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \
-I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/focaltech_mmi
obj-m := focaltech_mmi.o
focaltech_mmi-objs += focaltech_ts.o
focaltech_mmi-objs += focaltech_flash.o
focaltech_mmi-objs += focaltech_upgrade_ft8716.o
focaltech_mmi-objs += focaltech_upgrade_idc.o
focaltech_mmi-objs += focaltech_upgrade_ft5x46.o
focaltech_mmi-objs += focaltech_upgrade_ft8006u.o

View file

@ -0,0 +1,10 @@
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
clean:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,230 @@
#ifndef __LINUX_FOCALTECH_FLASH_H__
#define __LINUX_FOCALTECH_FLASH_H__
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input/focaltech_mmi_modules.h>
#include "focaltech_upgrade_common.h"
extern int fts_ctpm_auto_upgrade(struct i2c_client *client,
const char *fw_name,
const struct ft_ts_platform_data *pdata);
int fts_ctpm_i2c_hid2std(struct i2c_client *client);
#include <linux/fs.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/input/mt.h>
extern bool FTS_AUTO_LIC_UPGRADE_EN;
struct ts_ic_info {
bool is_incell;
bool hid_supported;
struct ft_chip_t ids;
};
struct fts_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct ts_ic_info ic_info;
struct workqueue_struct *ts_workqueue;
struct delayed_work esdcheck_work;
struct ft_ts_platform_data *pdata;
};
extern struct fts_ts_data *fts_data;
#define INTERVAL_READ_REG 100 /* unit:ms */
#define TIMEOUT_READ_REG 1000 /* unit:ms */
#define FTS_GET_VENDOR_ID_NUM 0
#define FTS_REG_LIC_VER 0xE4
#define BYTE_OFF_0(x) (u8)((x) & 0xFF)
#define BYTE_OFF_8(x) (u8)((x >> 8) & 0xFF)
#define BYTE_OFF_16(x) (u8)((x >> 16) & 0xFF)
#define BYTE_OFF_24(x) (u8)((x >> 24) & 0xFF)
#define FTS_CMD_START1 0x55
#define FTS_CMD_START2 0xAA
#define FTS_CMD_READ_ID 0x90
#define INTERVAL_READ_REG 100 //unit:ms
#define TIMEOUT_READ_REG 1000 //unit:ms
#define FTS_REG_IDE_PARA_VER_ID 0xB5
#define FTS_REG_IDE_PARA_STATUS 0xB6
#define FTS_REG_VENDOR_ID 0xA8
#define FTS_REG_MODULE_ID 0xE3
#define FTS_CMD_RESET 0x07
#define FTS_ROMBOOT_CMD_WRITE 0xAE
#define FTS_ROMBOOT_CMD_START_APP 0x08
#define FTS_DELAY_PRAMBOOT_START 10
#define FTS_ROMBOOT_CMD_ECC 0xCC
#define FTS_CMD_READ 0x03
#define FTS_CMD_READ_DELAY 1
#define FTS_CMD_READ_LEN 4
#define FTS_CMD_FLASH_TYPE 0x05
#define FTS_CMD_FLASH_MODE 0x09
#define FLASH_MODE_WRITE_FLASH_VALUE 0x0A
#define FLASH_MODE_UPGRADE_VALUE 0x0B
#define FLASH_MODE_LIC_VALUE 0x0C
#define FLASH_MODE_PARAM_VALUE 0x0D
#define FTS_CMD_ERASE_APP 0x61
#define FTS_REASE_APP_DELAY 1350
#define FTS_ERASE_SECTOR_DELAY 60
#define FTS_RETRIES_REASE 50
#define FTS_RETRIES_DELAY_REASE 200
#define FTS_CMD_FLASH_STATUS 0x6A
#define FTS_CMD_FLASH_STATUS_LEN 2
#define FTS_CMD_FLASH_STATUS_NOP 0x0000
#define FTS_CMD_FLASH_STATUS_ECC_OK 0xF055
#define FTS_CMD_FLASH_STATUS_ERASE_OK 0xF0AA
#define FTS_CMD_FLASH_STATUS_WRITE_OK 0x1000
#define FTS_CMD_ECC_INIT 0x64
#define FTS_CMD_ECC_CAL 0x65
#define FTS_CMD_ECC_CAL_LEN 6
#define FTS_RETRIES_ECC_CAL 10
#define FTS_RETRIES_DELAY_ECC_CAL 50
#define FTS_CMD_ECC_READ 0x66
#define FTS_CMD_DATA_LEN 0xB0
#define FTS_CMD_DATA_LEN_LEN 4
#define FTS_CMD_WRITE 0xBF
#define FTS_RETRIES_WRITE 100
#define FTS_RETRIES_DELAY_WRITE 1
#define FTS_CMD_WRITE_LEN 6
#define FTS_DELAY_READ_ID 20
#define FTS_DELAY_UPGRADE_RESET 80
#define PRAMBOOT_MIN_SIZE 0x120
#define PRAMBOOT_MAX_SIZE (64*1024)
#define FTS_FLASH_PACKET_LENGTH 32 /* max=128 */
#define FTS_MAX_LEN_ECC_CALC 0xFFFE /* must be even */
#define FTS_MIN_LEN 0x120
#define FTS_MAX_LEN_FILE (128 * 1024)
#define FTS_MAX_LEN_APP (64 * 1024)
#define FTS_MAX_LEN_SECTOR (4 * 1024)
#define FTS_CONIFG_VENDORID_OFF 0x04
#define FTS_CONIFG_MODULEID_OFF 0x1E
#define FTS_CONIFG_PROJECTID_OFF 0x20
#define FTS_APPINFO_OFF 0x100
#define FTS_APPINFO_APPLEN_OFF 0x00
#define FTS_APPINFO_APPLEN2_OFF 0x12
#define FTS_REG_UPGRADE 0xFC
#define FTS_UPGRADE_AA 0xAA
#define FTS_UPGRADE_55 0x55
#define FTS_DELAY_FC_AA 10
#define FTS_UPGRADE_LOOP 30
#define FTS_HEADER_LEN 32
#define FTS_FW_BIN_FILEPATH "/sdcard/"
#define FTX_MAX_COMPATIBLE_TYPE 4
#define FTS_ROMBOOT_CMD_ECC_NEW_LEN 7
#define FTS_ROMBOOT_CMD_ECC_FINISH 0xCE
#define FTS_CMD_READ_ECC 0xCD
#define AL2_FCS_COEF_8006 ((1 << 15) + (1 << 10) + (1 << 3))
#define I2C_BUFFER_LENGTH_MAXINUM 256
#define FILE_NAME_LENGTH 128
#define ENABLE 1
#define DISABLE 0
#define VALID 1
#define INVALID 0
#define FTS_CMD_START1 0x55
#define FTS_CMD_START2 0xAA
#define FTS_CMD_START_DELAY 10
#define FTS_CMD_READ_ID 0x90
#define FTS_CMD_READ_ID_LEN 4
#define FTS_CMD_READ_ID_LEN_INCELL 1
#define FTS_REG_ESD_SATURATE 0xED
#define FTS_REG_ESDCHECK_DISABLE 0x8D
#define FTS_SYSFS_ECHO_ON(buf) (buf[0] == '1')
#define FTS_SYSFS_ECHO_OFF(buf) (buf[0] == '0')
enum FW_FLASH_MODE {
FLASH_MODE_APP,
FLASH_MODE_LIC,
FLASH_MODE_PARAM,
FLASH_MODE_ALL,
};
/*****************************************************************************
* Private enumerations, structures and unions using typedef
*****************************************************************************/
/* IC info */
struct upgrade_func {
u64 ctype[FTX_MAX_COMPATIBLE_TYPE];
int newmode;
u32 fwveroff;
u32 fwcfgoff;
u32 appoff;
u32 licoff;
u32 paramcfgoff;
u32 paramcfgveroff;
u32 paramcfg2off;
bool hid_supported;
bool pramboot_supported;
bool fts_8006u;
u8 *pramboot;
u32 pb_length;
int (*init)(void);
int (*upgrade)(struct i2c_client *, u8 *, u32);
int (*get_hlic_ver)(u8 *);
int (*lic_upgrade)(struct i2c_client *, u8 *, u32);
int (*param_upgrade)(struct i2c_client *, u8 *, u32);
int (*force_upgrade)(struct i2c_client *, u8 *, u32);
};
struct fts_upgrade {
u8 *fw;
u32 fw_length;
u8 *lic;
u32 lic_length;
struct upgrade_func *func;
};
struct upgrade_fw {
u16 vendor_id;
u8 *fw_file;
u32 fw_len;
};
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
extern struct fts_upgrade *fwupgrade;
extern struct upgrade_func upgrade_func_ft8006;
extern struct upgrade_func upgrade_func_ft8006u;
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
bool fts_fwupg_check_fw_valid(struct i2c_client *client);
int fts_fwupg_get_boot_state(struct i2c_client *client, enum FW_STATUS *fw_sts);
bool fts_fwupg_check_state(struct i2c_client *client, enum FW_STATUS rstate);
int fts_fwupg_reset_in_boot(struct i2c_client *client);
int fts_fwupg_reset_to_boot(struct i2c_client *client);
int fts_fwupg_reset_to_romboot(struct i2c_client *client);
int fts_fwupg_enter_into_boot(struct i2c_client *client);
int fts_fwupg_erase(struct i2c_client *client, u32 delay);
int fts_fwupg_ecc_cal(struct i2c_client *client, u32 saddr, u32 len);
int fts_flash_write_buf(struct i2c_client *client, u32 saddr, u8 *buf, u32 len, u32 delay);
void fts_fwupg_auto_upgrade(struct fts_ts_data *ts_data);
void fts_i2c_hid2std(struct i2c_client *client);
int fts_ft8006u_pram_write_remap(struct i2c_client *client);
int fts_pram_write_buf(struct i2c_client *client, u8 *buf, u32 len);
int fts_pram_ecc_cal(struct i2c_client *client, u32 saddr, u32 len);
int fts_pram_start(struct i2c_client *client);
int fts_fwupg_do_upgrade(const char *fwname);
int fts_extra_init(struct i2c_client *client, struct input_dev *input_dev, struct ft_ts_platform_data *pdata);
int fts_extra_exit(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,178 @@
#ifndef __LINUX_FOCALTECH_UPGRADE_COMMON_H__
#define __LINUX_FOCALTECH_UPGRADE_COMMON_H__
#include <linux/i2c.h>
#include <linux/types.h>
#include "focaltech_flash.h"
#define FTS_MAX_TRIES 5
#define FTS_RETRY_DLY 20
#define FTS_MAX_WR_BUF 10
#define FTS_MAX_RD_BUF 2
#define FTS_FW_PKT_META_LEN 6
#define FTS_FW_PKT_DLY_MS 20
#define FTS_FW_LAST_PKT 0x6ffa
#define FTS_EARSE_DLY_MS 100
#define FTS_55_AA_DLY_NS 5000
#define FTS_CAL_START 0x04
#define FTS_CAL_FIN 0x00
#define FTS_CAL_STORE 0x05
#define FTS_CAL_RETRY 100
#define FTS_REG_CAL 0x00
#define FTS_CAL_MASK 0x70
#define FTS_BLOADER_SIZE_OFF 12
#define FTS_BLOADER_NEW_SIZE 30
#define FTS_DATA_LEN_OFF_OLD_FW 8
#define FTS_DATA_LEN_OFF_NEW_FW 14
#define FTS_FINISHING_PKT_LEN_OLD_FW 6
#define FTS_FINISHING_PKT_LEN_NEW_FW 12
#define FTS_MAGIC_BLOADER_Z7 0x7bfa
#define FTS_MAGIC_BLOADER_LZ4 0x6ffa
#define FTS_MAGIC_BLOADER_GZF_30 0x7ff4
#define FTS_MAGIC_BLOADER_GZF 0x7bf4
#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 BL_VERSION_LZ4 0
#define BL_VERSION_Z7 1
#define BL_VERSION_GZF 2
#define FTS_PACKET_LENGTH 128
#define FTS_SETTING_BUF_LEN 128
#define FTS_UPGRADE_LOOP 30
#define FTS_MAX_POINTS_2 2
#define FTS_MAX_POINTS_5 5
#define FTS_MAX_POINTS_10 10
#define AUTO_CLB_NEED 1
#define AUTO_CLB_NONEED 0
#define FTS_UPGRADE_AA 0xAA
#define FTS_UPGRADE_55 0x55
/* 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
#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(x) ((x) & FLAGBITS(0, FLAG_ICSERIALS_LEN - 1))
#define FTS_CHIP_IDC(x) (((x) & FLAGBIT(FLAG_IDC_BIT)) == \
FLAGBIT(FLAG_IDC_BIT))
#define FTS_DEBUG pr_debug
#define FTS_ERROR pr_err
#define FTS_INFO pr_info
#define FTS_FUNC_ENTER() pr_debug("[FTS]%s: Enter\n", __func__)
#define FTS_FUNC_EXIT() pr_debug("[FTS]%s: Exit(%d)\n", __func__, \
__LINE__)
enum ENUM_APP_INFO {
APP_LEN = 0x00,
APP_LEN_NE = 0x02,
APP_P1_ECC = 0x04,
APP_P1_ECC_NE = 0x06,
APP_P2_ECC = 0x08,
APP_P2_ECC_NE = 0x0A,
APP_LEN_H = 0x12,
APP_LEN_H_NE = 0x14,
APP_BLR_ID = 0x1C,
APP_BLR_ID_NE = 0x1D,
PBOOT_ID_H = 0x1E,
PBOOT_ID_L = 0x1F
};
enum FW_STATUS {
FTS_RUN_IN_ERROR,
FTS_RUN_IN_APP,
FTS_RUN_IN_ROM,
FTS_RUN_IN_PRAM,
FTS_RUN_IN_BOOTLOADER
};
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;
unsigned long chip_type;
};
struct fts_upgrade_fun {
int (*get_app_bin_file_ver)(const char *);
int (*upgrade_with_app_bin_file)(struct i2c_client *, const char *);
int (*upgrade_with_lcd_cfg_bin_file)(struct i2c_client *, const char *);
};
extern int fts_i2c_read(struct i2c_client *client,
char *writebuf, int writelen,
char *readbuf, int readlen);
extern int fts_i2c_write(struct i2c_client *client,
char *writebuf, int writelen);
extern int fts_i2c_write_reg(struct i2c_client *client,
u8 addr, const u8 val);
extern int fts_i2c_read_reg(struct i2c_client *client, u8 addr, u8 *val);
extern enum FW_STATUS fts_ctpm_get_pram_or_rom_id
(struct i2c_client *client);
extern bool fts_ecc_check(const u8 *pbt_buf,
u32 star_addr, u32 len, u16 ecc_addr);
static inline u16 fts_data_word(const u8 *pbt_buf, u32 addr)
{
return ((u16)pbt_buf[addr] << 8) + pbt_buf[addr + 1];
}
extern int fts_ctpm_upgrade_idc_init(struct i2c_client *client,
u32 dw_length);
extern void fts_ctpm_start_pramboot(struct i2c_client *client);
extern int fts_ctpm_start_fw_upgrade(struct i2c_client *client);
extern bool fts_ctpm_check_run_state(struct i2c_client *client,
int state);
extern int fts_ctpm_upgrade_ecc(struct i2c_client *client,
u32 startaddr, u32 length);
extern int fts_ctpm_pramboot_ecc(struct i2c_client *client);
extern int fts_ctpm_erase_flash(struct i2c_client *client);
extern int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client,
u32 length, const u8 *readbuf);
extern int fts_ctpm_write_app_for_idc(struct i2c_client *client,
u32 length, const u8 *readbuf);
extern void ft8716_set_upgrade_function(struct fts_upgrade_fun **curr);
extern void ft8716_set_chip_id(struct ft_chip_t **curr);
extern void ft5x46_set_upgrade_function(struct fts_upgrade_fun **curr);
extern void ft5x46_set_chip_id(struct ft_chip_t **curr);
#endif

View file

@ -0,0 +1,451 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2010-2016, 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.
*
*/
#include <linux/firmware.h>
#include "focaltech_flash.h"
#include "focaltech_upgrade_common.h"
#define APP_FILE_MAX_SIZE (60 * 1024)
#define APP_FILE_MIN_SIZE (8)
#define CONFIG_START_ADDR (0xD780)
#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)
static int fts_5x46_get_app_bin_file_ver(const char *firmware_name);
static int fts_5x46_fw_upgrade_with_app_bin_file(
struct i2c_client *client, const char *firmware_name);
static struct fts_upgrade_fun fts_updatefun_5x46 = {
.get_app_bin_file_ver = fts_5x46_get_app_bin_file_ver,
.upgrade_with_app_bin_file = fts_5x46_fw_upgrade_with_app_bin_file,
.upgrade_with_lcd_cfg_bin_file = NULL,
};
static struct ft_chip_t fts_chip_type_5x46 = {
.type = 0x02,
.chip_idh = 0x54,
.chip_idl = 0x22,
.rom_idh = 0x54,
.rom_idl = 0x22,
.pramboot_idh = 0x00,
.pramboot_idl = 0x00,
.bootloader_idh = 0x54,
.bootloader_idl = 0x2C,
.chip_type = 0x54220002,
};
inline void ft5x46_set_upgrade_function(struct fts_upgrade_fun **curr)
{
*curr = &fts_updatefun_5x46;
}
inline void ft5x46_set_chip_id(struct ft_chip_t **curr)
{
*curr = &fts_chip_type_5x46;
}
static int fts_5x46_get_app_bin_file_ver(const char *firmware_name)
{
int fw_ver = 0;
int rc;
const struct firmware *fw = NULL;
FTS_FUNC_ENTER();
rc = request_firmware(&fw, firmware_name, NULL);
if (rc < 0) {
FTS_ERROR("[UPGRADE] Request firmware failed - %s (%d)\n",
firmware_name, rc);
return rc;
}
if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) {
FTS_ERROR("[UPGRADE] FW length(%zd) error\n", fw->size);
return -EIO;
goto file_ver_rel_fw;
}
fw_ver = fw->data[fw->size - 2];
file_ver_rel_fw:
release_firmware(fw);
FTS_FUNC_EXIT();
return fw_ver;
}
/************************************************************************
* Name: fts_ft5436_upgrade_use_buf
* Brief: fw upgrade
* Input: i2c info, file buf, file len
* Output: no
* Return: fail <0
***********************************************************************/
static int fts_ft5x46_upgrade_use_buf(struct i2c_client *client,
const 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++)
{
/*********Step 1:Reset CTPM *****/
fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA);
msleep(10);
fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55);
msleep(200);
/*********Step 2:Enter upgrade mode *****/
fts_ctpm_i2c_hid2std(client);
msleep(5);
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;
}
/*********Step 3:Check bootloader ID *****/
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] == 0x54) && (reg_val[1] != 0))
{
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)
{
FTS_ERROR("[UPGRADE]: failed writing 0x55 and 0xaa : i = %d!!", i);
return -EIO;
}
/*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(1350);
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] = (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);
/*********Step 5:write firmware(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] = 0x00;
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(10);
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;
}
FTS_DEBUG("[UPGRADE]: reg_val[0] = %x reg_val[1] = %x!!", reg_val[0], reg_val[1]);
//msleep(1);
msleep(1000);
}
}
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(10);
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;
}
FTS_DEBUG("[UPGRADE]: reg_val[0] = %x reg_val[1] = %x reg_val[2] = 0x%x!!", reg_val[0], reg_val[1], (((packet_number * FTS_PACKET_LENGTH)/((dw_lenth) % FTS_PACKET_LENGTH))+0x1000));
//msleep(1);
msleep(100);
}
}
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 = 0;
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;
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);
FTS_DEBUG("[UPGRADE]: reg_val[0]=%02x reg_val[0]=%02x!!", reg_val[0], reg_val[1]);
if ((0xF0 == reg_val[0]) && (0x55 == reg_val[1]))
{
break;
}
msleep(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(200);
fts_ctpm_i2c_hid2std(client);
return 0;
}
#define AL2_FCS_COEF ((1 << 7) + (1 << 6) + (1 << 5))
/*****************************************************************************
* Name: ecc_calc
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
static u8 ecc_calc(const u8 *pbt_buf, u16 start, u16 length)
{
u8 cFcs = 0;
u16 i, j;
for ( i = 0; i < length; i++ )
{
cFcs ^= pbt_buf[start++];
for (j = 0; j < 8; j ++)
{
if (cFcs & 1)
{
cFcs = (u8)((cFcs >> 1) ^ AL2_FCS_COEF);
}
else
{
cFcs >>= 1;
}
}
}
return cFcs;
}
/*****************************************************************************
* Name: fts_check_app_bin_valid
* Brief:
* Input:
* Output:
* Return:
*****************************************************************************/
static bool fts_5x46_check_app_bin_valid(const u8 *pbt_buf, u32 dw_lenth)
{
u8 ecc1;
u8 ecc2;
u16 len1;
u16 len2;
u8 cal_ecc;
u16 usAddrInfo;
/* 1. First Byte */
if (pbt_buf[0] != 0x02)
{
FTS_DEBUG("[UPGRADE]APP.BIN Verify- the first byte(%x) error", pbt_buf[0]);
return false;
}
usAddrInfo = dw_lenth - 8;
/* 2.len */
len1 = pbt_buf[usAddrInfo++] << 8;
len1 += pbt_buf[usAddrInfo++];
len2 = pbt_buf[usAddrInfo++] << 8;
len2 += pbt_buf[usAddrInfo++];
if ((len1 + len2) != 0xFFFF)
{
FTS_DEBUG("[UPGRADE]APP.BIN Verify- LENGTH(%04x) XOR error", len1);
return false;
}
/* 3.ecc */
ecc1 = pbt_buf[usAddrInfo++];
ecc2 = pbt_buf[usAddrInfo++];
if ((ecc1 + ecc2) != 0xFF)
{
FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC(%x) XOR error", ecc1);
return false;
}
cal_ecc = ecc_calc(pbt_buf, 0x0, len1);
if (ecc1 != cal_ecc)
{
FTS_DEBUG("[UPGRADE]APP.BIN Verify- ECC calc error");
return false;
}
return true;
}
/************************************************************************
* Name: fts_5436_fw_upgrade_with_app_bin_file
* Brief: upgrade with *.bin file
* Input: i2c info, file name
* Output: no
* Return: success =0
***********************************************************************/
static int fts_5x46_fw_upgrade_with_app_bin_file(struct i2c_client *client, const char *firmware_name)
{
int i_ret = 0;
bool ecc_ok = false;
const struct firmware *fw = NULL;
FTS_INFO("[UPGRADE] start upgrade with app.bin\n");
i_ret = request_firmware(&fw, firmware_name, &client->dev);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] Request firmware failed - %s (%d)\n",
firmware_name, i_ret);
return i_ret;
}
if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) {
FTS_ERROR("[UPGRADE] FW length(%zd) error\n", fw->size);
i_ret = -EINVAL;
goto file_upgrade_rel_fw;
}
ecc_ok = fts_5x46_check_app_bin_valid(fw->data, fw->size);
if (ecc_ok)
{
FTS_INFO("[UPGRADE] app.bin ecc ok");
i_ret = fts_ft5x46_upgrade_use_buf(client, fw->data, fw->size);
if (i_ret != 0)
{
FTS_ERROR("[UPGRADE]: upgrade app.bin failed");
}
else
{
FTS_INFO("[UPGRADE]: upgrade app.bin succeed");
}
}
else
{
FTS_ERROR("[UPGRADE] app.bin ecc failed");
}
return i_ret;
file_upgrade_rel_fw:
release_firmware(fw);
return i_ret;
}

View file

@ -0,0 +1,944 @@
/*
*
* 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_ft8006u.c
*
* Author: Focaltech Driver Team
*
* Created: 2017-07-22
*
* Abstract:
*
* Reference:
*
*****************************************************************************/
/*****************************************************************************
* 1.Included header files
*****************************************************************************/
#include "focaltech_flash.h"
/*****************************************************************************
* Global variable or extern global variabls/functions
*****************************************************************************/
#define FT8006U_PRAMBOOT_FW_NAME "FT8006U_Pramboot.bin"
/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define MAX_BANK_DATA 0x80
#define MAX_GAMMA_LEN 0x180
#define LIC_CHECKSUM_H_OFF 0x01
#define LIC_CHECKSUM_L_OFF 0x00
#define LIC_LCD_ECC_H_OFF 0x05
#define LIC_LCD_ECC_L_OFF 0x04
#define LIC_BANKECC_H_OFF 0x0F
#define LIC_BANKECC_L_OFF 0x0E
#define LIC_REG_2 0xB2
#define LIC_BANK_START_ADDR 0x0A
static int gamma_enable[] = { 0x042c, 0x91, 0x80, 0x00, 0x12, 0x01 };
bool gamma_has_enable = false;
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;
};
/*****************************************************************************
* Static function prototypes
*****************************************************************************/
/* 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[3] << 8) + buf[2]);
if ((file_len >= FTS_MAX_LEN_SECTOR) || (file_len <= FTS_MIN_LEN)) {
FTS_ERROR("host lcd init code len(%x) is too large", file_len);
return -EINVAL;
}
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 = LIC_BANK_START_ADDR; /* 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]);
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;
if ((bank_num == 0x15) || (bank_num == 0x16))
bank_num = 0x14;
if (bank_num == 0x1B)
bank_num = 0x1A;
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 {
if ((bank_crc_en >> banknum) & 0x01) {
for (i = 0; i < bank_len; i++) {
temp_byte.dshort = (u16)bank_data[i];
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;
return 0;
}
/* calculate lcd init code checksum */
static u16 cal_lcdinitcode_checksum(u8 *ptr , int length)
{
/* CRC16 */
u16 cfcs = 0;
int i = 0;
int j = 0;
length = (length % 2 == 0) ? length : (length - 1);
for (i = 0; i < length; i += 2) {
cfcs ^= ((ptr[i] << 8) + ptr[i + 1]);
for (j = 0; j < 16; j++) {
if (cfcs & 1)
cfcs = (u16)((cfcs >> 1) ^ ((1 << 15) + (1 << 10) + (1 << 3)));
else
cfcs >>= 1;
}
}
return cfcs;
}
/*
* check_initial_code_valid - check initial code valid or not
*/
static int check_initial_code_valid(struct i2c_client *client, u8 *buf)
{
int ret = 0;
u16 initcode_ecc = 0;
u16 buf_ecc = 0;
u16 initcode_checksum = 0;
u16 buf_checksum = 0;
u16 hlic_len = 0;
hlic_len = (u16)(((u16)buf[3]) << 8) + buf[2];
if ((hlic_len >= FTS_MAX_LEN_SECTOR) || (hlic_len <= FTS_MIN_LEN)) {
FTS_ERROR("host lcd init code len(%x) is too large", hlic_len);
return -EINVAL;
}
initcode_checksum = cal_lcdinitcode_checksum(buf + 2, hlic_len - 2);
buf_checksum = ((u16)((u16)buf[1] << 8) + buf[0]);
FTS_DEBUG("lcd init code calc checksum:0x%04x,0x%04x", initcode_checksum, buf_checksum);
if (initcode_checksum != buf_checksum) {
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;
}
buf_ecc = ((u16)((u16)buf[5] << 8) + buf[4]);
FTS_DEBUG("lcd init code cal ecc:%04x, %04x", initcode_ecc, buf_ecc);
if (initcode_ecc != buf_ecc) {
FTS_ERROR("Initial Code ecc check fail");
return -EINVAL;
}
return 0;
}
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;
}
/*
* description : find the address of one bank in initcode
*
* parameters :
* initcode : initcode
* bank_start_addr - the address of one bank, search bank from this address
* bank_sign - bank signature, 2 bytes
* bank_pos - return the position of the bank
* return: return 0 if success, otherwise return error code
*/
static int find_bank(
u8 *initcode,
u16 bank_start_addr,
u16 bank_sign,
u16 *bank_pos)
{
u16 file_len = 0;
u16 pos = 0;
u8 bank[2] = { 0 };
file_len = (u16)(((u16)initcode[3] << 8) + initcode[2]);
if ((file_len >= FTS_MAX_LEN_SECTOR) || (file_len <= FTS_MIN_LEN)) {
FTS_ERROR("host lcd init code len(%x) is too large", file_len);
return -EINVAL;
}
bank[0] = bank_sign >> 8;
bank[1] = bank_sign;
pos = bank_start_addr;
while (pos < file_len) {
if ((initcode[pos] == bank[0])
&& (initcode[pos + 1] == bank[1])) {
FTS_INFO("bank(%x %x) find", bank[0], bank[1]);
*bank_pos = pos;
return 0;
} else {
pos += ((u16)initcode[pos + 2] << 8 ) + initcode[pos + 3] + 4;
}
}
return -ENODATA;
}
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;
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_DEBUG("backup_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)
{
int ret = 0;
u16 gamma_pos = 0;
int gamma_analog[] = {0x003B, 0x85, 0x00, 0x00, 0x2D, 0x2D};
int gamma_digital1[] = {0x0374, 0x8D, 0x00, 0x00, 0x80, 0x80};
int gamma_digital2[] = {0x03F8, 0x8D, 0x80, 0x00, 0x14, 0x14};
u16 bank_addr = 0;
u16 bank_saddr = 0;
u16 bank_sign = 0;
u16 bank_len = 0;
/* Analog Gamma */
bank_saddr = LIC_BANK_START_ADDR;
bank_sign = ((u16)gamma_analog[1] << 8) + gamma_analog[2];
ret = find_bank(initcode, LIC_BANK_START_ADDR, bank_sign, &bank_addr);
if (ret < 0) {
FTS_ERROR("find bank analog gamma fail");
goto find_gamma_bank_err;
}
bank_len = ((u16)initcode[bank_addr + 2] << 8 ) + initcode[bank_addr + 3];
memcpy(initcode + bank_addr + 4 , gamma + gamma_pos + 4, bank_len);
initcode[bank_addr + 4] = 0xA5;
gamma_pos += bank_len + 4;
/* Digital1 Gamma */
bank_saddr = bank_addr;
bank_sign = ((u16)gamma_digital1[1] << 8) + gamma_digital1[2];
ret = find_bank(initcode, bank_saddr, bank_sign, &bank_addr);
if (ret < 0) {
FTS_ERROR("find bank analog gamma fail");
goto find_gamma_bank_err;
}
bank_len = ((u16)initcode[bank_addr + 2] << 8 ) + initcode[bank_addr + 3];
memcpy(initcode + bank_addr + 4 , gamma + gamma_pos + 4, bank_len);
gamma_pos += bank_len + 4;
/* Digital2 Gamma */
bank_saddr = bank_addr;
bank_sign = ((u16)gamma_digital2[1] << 8) + gamma_digital2[2];
ret = find_bank(initcode, bank_saddr, bank_sign, &bank_addr);
if (ret < 0) {
FTS_ERROR("find bank analog gamma fail");
goto find_gamma_bank_err;
}
bank_len = ((u16)initcode[bank_addr + 2] << 8 ) + initcode[bank_addr + 3];
memcpy(initcode + bank_addr + 4 , gamma + gamma_pos + 4, bank_len);
gamma_pos += bank_len + 4;
/* enable Gamma */
bank_saddr = bank_addr;
bank_sign = ((u16)gamma_enable[1] << 8) + gamma_enable[2];
ret = find_bank(initcode, bank_saddr, bank_sign, &bank_addr);
if (ret < 0) {
FTS_ERROR("find bank analog gamma fail");
goto find_gamma_bank_err;
}
if (gamma[gamma_pos + 4])
initcode[bank_addr + 4 + 15] |= 0x01;
else
initcode[bank_addr + 4 + 15] &= 0xFE;
gamma_pos += 1 + 4;
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 cal_replace_ecc(u8 *initcode)
{
int ret = 0;
u16 initcode_ecc = 0;
u16 bank31 = 0x9200;
u16 bank31_addr = 0;
ret = cal_lcdinitcode_ecc(initcode, &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);
initcode[LIC_LCD_ECC_H_OFF] = (u8)(initcode_ecc >> 8);
initcode[LIC_LCD_ECC_L_OFF] = (u8)(initcode_ecc);
ret = find_bank(initcode, LIC_BANK_START_ADDR, bank31, &bank31_addr);
if (ret < 0) {
FTS_ERROR("find bank 31 fail");
return ret;
}
FTS_INFO("lcd init code ecc bank addr:0x%04x", bank31_addr);
initcode[bank31_addr + LIC_BANKECC_H_OFF + 4] = (u8)(initcode_ecc >> 8);
initcode[bank31_addr + LIC_BANKECC_L_OFF + 4] = (u8)(initcode_ecc);
return 0;
}
/*
* read_replace_3gamma - read and replace 3-gamma data
*/
static int read_replace_3gamma(struct i2c_client *client, u8 *buf, bool flag)
{
int ret = 0;
u16 initcode_checksum = 0;
u8 *tmpbuf = NULL;
u8 *gamma = NULL;
u16 gamma_len = 0;
u16 hlic_len = 0;
int base_addr = 0;
int i = 0;
FTS_FUNC_ENTER();
ret = read_3gamma(client, &gamma, &gamma_len);
if (ret < 0) {
FTS_INFO("no vaid 3-gamma data, not replace");
if (gamma) {
kfree(gamma);
gamma = NULL;
}
return 0;
}
base_addr = 0;
for (i = 0; i < 2; i++) {
if (i == 1) {
if (flag == true)
base_addr = 0x7C0;
else
break;
}
tmpbuf = buf + base_addr;
ret = replace_3gamma(tmpbuf, gamma, gamma_len);
if (ret < 0) {
FTS_ERROR("replace 3-gamma fail");
goto REPLACE_GAMMA_ERR;
}
ret = cal_replace_ecc(tmpbuf);
if (ret < 0) {
FTS_ERROR("lcd init code ecc calculate/replace fail");
goto REPLACE_GAMMA_ERR;
}
hlic_len = (u16)(((u16)tmpbuf[3]) << 8) + tmpbuf[2];
if ((hlic_len >= FTS_MAX_LEN_SECTOR) || (hlic_len <= FTS_MIN_LEN)) {
FTS_ERROR("host lcd init code len(%x) is too large", hlic_len);
ret = -EINVAL;
goto REPLACE_GAMMA_ERR;
}
initcode_checksum = cal_lcdinitcode_checksum(tmpbuf + 2, hlic_len - 2);
FTS_INFO("lcd init code calc checksum:0x%04x", initcode_checksum);
tmpbuf[LIC_CHECKSUM_H_OFF] = (u8)(initcode_checksum >> 8);
tmpbuf[LIC_CHECKSUM_L_OFF] = (u8)(initcode_checksum);
}
if (gamma) {
kfree(gamma);
gamma = NULL;
}
FTS_FUNC_EXIT();
return 0;
REPLACE_GAMMA_ERR:
if (gamma) {
kfree(gamma);
gamma = NULL;
}
return ret;
}
static int fts_ft8006u_upgrade_mode(
struct i2c_client *client,
enum FW_FLASH_MODE mode,
u8 *buf,
u32 len)
{
int ret = 0;
bool flag = false;
u32 start_addr = 0;
u8 cmd[4] = { 0 };
u32 delay = 0;
int ecc_in_host = 0;
int ecc_in_tp = 0;
if ((NULL == buf) || (len < FTS_MIN_LEN)) {
FTS_ERROR("buffer/len(%x) is invalid", len);
return -EINVAL;
}
/* enter into upgrade environment */
ret = fts_fwupg_enter_into_boot(client);
if (ret < 0) {
FTS_ERROR("enter into pramboot/bootloader fail,ret=%d", ret);
goto fw_reset;
}
cmd[0] = FTS_CMD_FLASH_MODE;
cmd[1] = FLASH_MODE_UPGRADE_VALUE;
start_addr = upgrade_func_ft8006u.appoff;
if (FLASH_MODE_LIC == mode) {
/* lcd initial code upgrade */
/* read replace 3-gamma yet */
ret = read_replace_3gamma(client, buf, flag);
if (ret < 0) {
FTS_ERROR("replace 3-gamma fail, not upgrade lcd init code");
goto fw_reset;
}
cmd[1] = FLASH_MODE_LIC_VALUE;
start_addr = upgrade_func_ft8006u.licoff;
} else if (FLASH_MODE_PARAM == mode) {
cmd[1] = FLASH_MODE_PARAM_VALUE;
start_addr = upgrade_func_ft8006u.paramcfgoff;
}
FTS_DEBUG("flash mode:0x%02x, start addr=0x%04x", cmd[1], start_addr);
ret = fts_i2c_write(client, cmd, 2);
if (ret < 0) {
FTS_ERROR("upgrade mode(09) cmd write fail");
goto fw_reset;
}
delay = FTS_ERASE_SECTOR_DELAY * (len / FTS_MAX_LEN_SECTOR);
ret = fts_fwupg_erase(client, delay);
if (ret < 0) {
FTS_ERROR("erase cmd write fail");
goto fw_reset;
}
/* write app */
ecc_in_host = fts_flash_write_buf(client, start_addr, buf, len, 1);
if (ecc_in_host < 0 ) {
FTS_ERROR("lcd initial code write fail");
goto fw_reset;
}
/* ecc */
ecc_in_tp = fts_fwupg_ecc_cal(client, start_addr, len);
if (ecc_in_tp < 0 ) {
FTS_ERROR("ecc read fail");
goto fw_reset;
}
FTS_INFO("ecc in tp:%x, host:%x", ecc_in_tp, ecc_in_host);
if (ecc_in_tp != ecc_in_host) {
FTS_ERROR("ecc check fail");
goto fw_reset;
}
FTS_INFO("upgrade success, reset to normal boot");
ret = fts_fwupg_reset_in_boot(client);
if (ret < 0)
FTS_ERROR("reset to normal boot fail");
msleep(400);
return 0;
fw_reset:
return -EIO;
}
/*
* fts_ft8006u_get_hlic_ver - read host lcd init code version
*
* return 0 if host lcd init code is valid, otherwise return error code
*/
static int fts_ft8006u_get_hlic_ver(u8 *initcode)
{
u8 *hlic_buf = initcode;
u16 hlic_len = 0;
u8 hlic_ver[2] = { 0 };
hlic_len = (u16)(((u16)hlic_buf[3]) << 8) + hlic_buf[2];
FTS_INFO("host lcd init code len:%x", hlic_len);
if ((hlic_len >= FTS_MAX_LEN_SECTOR) || (hlic_len <= FTS_MIN_LEN)) {
FTS_ERROR("host lcd init code len(%x) is too large", hlic_len);
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];
}
/************************************************************************
* Name: fts_ft8006u_upgrade
* Brief:
* Input:
* Output:
* Return: return 0 if success, otherwise return error code
***********************************************************************/
static int fts_ft8006u_upgrade(struct i2c_client *client, u8 *buf, u32 len)
{
int ret = 0;
u8 *tmpbuf = NULL;
u32 app_len = 0;
FTS_DEBUG("fw app upgrade...");
if (NULL == buf) {
FTS_ERROR("fw buf is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_FILE)) {
FTS_ERROR("fw buffer len(%x) fail", len);
return -EINVAL;
}
app_len = len - upgrade_func_ft8006u.appoff;
tmpbuf = buf + upgrade_func_ft8006u.appoff;
ret = fts_ft8006u_upgrade_mode(client, FLASH_MODE_APP, tmpbuf, app_len);
if (ret < 0) {
FTS_INFO("fw upgrade fail,reset to normal boot");
if (fts_fwupg_reset_in_boot(client) < 0)
FTS_ERROR("reset to normal boot fail");
return ret;
}
return 0;
}
/************************************************************************
* Name: fts_ft8006u_lic_upgrade
* Brief:
* Input:
* Output:
* Return: return 0 if success, otherwise return error code
***********************************************************************/
static int fts_ft8006u_lic_upgrade(struct i2c_client *client, u8 *buf, u32 len)
{
int ret = 0;
u8 *tmpbuf = NULL;
u32 lic_len = 0;
FTS_DEBUG("lcd initial code upgrade...");
if (NULL == buf) {
FTS_ERROR("lcd initial code buffer is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_FILE)) {
FTS_ERROR("lcd initial code buffer len(%x) fail", len);
return -EINVAL;
}
ret = check_initial_code_valid(client, buf);
if (ret < 0) {
FTS_ERROR("initial code invalid, not upgrade lcd init code");
return -EINVAL;
}
/* remalloc memory for initcode, need change content of initcode afterwise */
lic_len = FTS_MAX_LEN_SECTOR;
tmpbuf = kmalloc(lic_len, GFP_KERNEL);
if (NULL == tmpbuf) {
FTS_INFO("initial code buf malloc fail");
return -EINVAL;
}
memcpy(tmpbuf, buf, lic_len);
ret = fts_ft8006u_upgrade_mode(client, FLASH_MODE_LIC, tmpbuf, lic_len);
if (ret < 0) {
FTS_INFO("lcd initial code upgrade fail,reset to normal boot");
if (fts_fwupg_reset_in_boot(client) < 0)
FTS_ERROR("reset to normal boot fail");
if (tmpbuf) {
kfree(tmpbuf);
tmpbuf = NULL;
}
return ret;
}
if (tmpbuf) {
kfree(tmpbuf);
tmpbuf = NULL;
}
return 0;
}
/************************************************************************
* Name: fts_ft8006u_param_upgrade
* Brief:
* Input: buf - all.bin
* len - len of all.bin
* Output:
* Return: return 0 if success, otherwise return error code
***********************************************************************/
static int fts_ft8006u_param_upgrade(struct i2c_client *client, u8 *buf, u32 len)
{
int ret = 0;
u8 *tmpbuf = NULL;
u32 param_length = 0;
FTS_DEBUG("parameter configure upgrade...");
if (NULL == buf) {
FTS_ERROR("fw file buffer is null");
return -EINVAL;
}
if ((len < FTS_MIN_LEN) || (len > FTS_MAX_LEN_FILE)) {
FTS_ERROR("fw file buffer len(%x) fail", len);
return -EINVAL;
}
tmpbuf = buf + upgrade_func_ft8006u.paramcfgoff;
param_length = len - upgrade_func_ft8006u.paramcfgoff;
ret = fts_ft8006u_upgrade_mode(client, FLASH_MODE_PARAM, tmpbuf, param_length);
if (ret < 0) {
FTS_INFO("fw upgrade fail,reset to normal boot");
if (fts_fwupg_reset_in_boot(client) < 0)
FTS_ERROR("reset to normal boot fail");
return ret;
}
return 0;
}
/************************************************************************
* fts_ft8006u_pram_write_remap - write pramboot to pram and start pramboot
*
* return 0 if success, otherwise return error code
***********************************************************************/
int fts_ft8006u_pram_write_remap(struct i2c_client *client)
{
int ret = 0;
int ecc_in_host = 0;
int ecc_in_tp = 0;
u8 *pb_buf = NULL;
u32 pb_len = 0;
const struct firmware *fw = NULL;
//struct fts_upgrade *upg = fwupgrade;
FTS_INFO("[UPGRADE]write pram and remap\n");
ret = request_firmware(&fw, FT8006U_PRAMBOOT_FW_NAME, &client->dev);
if (ret < 0) {
FTS_ERROR("[UPGRADE] Request pramboot failed - %s (%d)\n",
FT8006U_PRAMBOOT_FW_NAME, ret);
return ret;
}
if (fw->size < FTS_MIN_LEN) {
FTS_ERROR("[UPGRADE]pramboot length(%x) fail\n", (unsigned int)fw->size);
return -EINVAL;
}
pb_buf = (u8*)fw->data;
pb_len= (u32)fw->size;
/* write pramboot to pram */
ecc_in_host = fts_pram_write_buf(client, pb_buf, pb_len);
if (ecc_in_host < 0) {
FTS_ERROR( "write pramboot fail");
return ecc_in_host;
}
/* read out checksum */
ecc_in_tp = fts_pram_ecc_cal(client, 0, pb_len);
if (ecc_in_tp < 0) {
FTS_ERROR( "read pramboot ecc fail");
return ecc_in_tp;
}
FTS_DEBUG("[UPGRADE]pram ecc in tp:%x, host:%x\n", ecc_in_tp, ecc_in_host);
/* pramboot checksum != fw checksum, upgrade fail */
if (ecc_in_host != ecc_in_tp) {
FTS_ERROR("[UPGRADE]pramboot ecc check fail\n");
return -EIO;
}
/*start pram*/
ret = fts_pram_start(client);
if (ret < 0) {
FTS_ERROR("[UPGRADE]pram start fail\n");
return ret;
}
return 0;
}
struct upgrade_func upgrade_func_ft8006u = {
.ctype = {0x0B},
.fwveroff = 0x210E,
.fwcfgoff = 0x1F80,
.appoff = 0x2000,
.licoff = 0x0000,
.paramcfgoff = 0x12000,
.paramcfgveroff = 0x12004,
.pramboot_supported = true,
.hid_supported = false,
.fts_8006u = true,
.upgrade = fts_ft8006u_upgrade,
.get_hlic_ver = fts_ft8006u_get_hlic_ver,
.lic_upgrade = fts_ft8006u_lic_upgrade,
.param_upgrade = fts_ft8006u_param_upgrade,
};

View file

@ -0,0 +1,396 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2010-2016, 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.
*
*/
#include <linux/firmware.h>
#include "focaltech_flash.h"
#include "focaltech_upgrade_common.h"
#define APP_FILE_MAX_SIZE (64 * 1024)
#define APP_FILE_MIN_SIZE (8)
#define APP_FILE_VER_MAPPING (0x10E)
#define APP_FILE_VENDORID_MAPPING (0x10C)
#define APP_FILE_CHIPID_MAPPING (0x11E)
#define CONFIG_START_ADDR (0x0000)
#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 FW_CFG_TOTAL_SIZE 0x00
#define APP1_START 0x00
#define APP1_LEN 0x100
#define APP_VERIF_ADDR (APP1_START + APP1_LEN)
#define APP_VERIF_LEN 0x20
#define APP1_ECC_ADDR (APP_VERIF_ADDR + APP_P1_ECC)
#define APP2_START (APP_VERIF_ADDR + APP_VERIF_LEN + \
FW_CFG_TOTAL_SIZE)
#define APP2_ECC_ADDR (APP_VERIF_ADDR + APP_P2_ECC)
#define FT8716_PRAMBOOT_FW_NAME "FT8716_Pramboot.bin"
static int fts_ctpm_get_app_bin_file_ver(const char *firmware_name);
static int fts_ctpm_fw_upgrade_with_app_bin_file(
struct i2c_client *client, const char *firmware_name);
static struct fts_upgrade_fun fts_updatefun_8716 = {
.get_app_bin_file_ver = fts_ctpm_get_app_bin_file_ver,
.upgrade_with_app_bin_file = fts_ctpm_fw_upgrade_with_app_bin_file,
.upgrade_with_lcd_cfg_bin_file = NULL,
};
static struct ft_chip_t fts_chip_type_8716 = {
.type = 0x05,
.chip_idh = 0x87,
.chip_idl = 0x16,
.rom_idh = 0x87,
.rom_idl = 0x16,
.pramboot_idh = 0x87,
.pramboot_idl = 0xA6,
.bootloader_idh = 0x00,
.bootloader_idl = 0x00,
.chip_type = 0x87160805,
};
inline void ft8716_set_upgrade_function(struct fts_upgrade_fun **curr)
{
*curr = &fts_updatefun_8716;
}
inline void ft8716_set_chip_id(struct ft_chip_t **curr)
{
*curr = &fts_chip_type_8716;
}
static int fts_ctpm_get_app_bin_file_ver(const char *firmware_name)
{
int fw_ver = 0;
int rc;
const struct firmware *fw = NULL;
FTS_FUNC_ENTER();
rc = request_firmware(&fw, firmware_name, NULL);
if (rc < 0) {
FTS_ERROR("[UPGRADE] Request firmware failed - %s (%d)\n",
firmware_name, rc);
return rc;
}
if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) {
FTS_ERROR("[UPGRADE] FW length(%zd) error\n", fw->size);
return -EIO;
goto file_ver_rel_fw;
}
fw_ver = fw->data[APP_FILE_VER_MAPPING];
file_ver_rel_fw:
release_firmware(fw);
FTS_FUNC_EXIT();
return fw_ver;
}
static int fts_ctpm_get_vendor_id_flash(struct i2c_client *client)
{
int i_ret = 0;
u8 vendorid[4] = {0};
u8 auc_i2c_write_buf[10];
u8 i = 0;
for (i = 0; i < FTS_UPGRADE_LOOP; i++) {
auc_i2c_write_buf[0] = 0x03;
auc_i2c_write_buf[1] = 0x00;
auc_i2c_write_buf[2] = (u8)((CONFIG_VENDOR_ID_ADDR - 1) >> 8);
auc_i2c_write_buf[3] = (u8)(CONFIG_VENDOR_ID_ADDR - 1);
i_ret = fts_i2c_read(client, auc_i2c_write_buf, 4, vendorid, 2);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] read flash i_ret = %d\n", i_ret);
continue;
}
break;
}
FTS_INFO("[UPGRADE] vendor id from flash rom: 0x%x\n", vendorid[1]);
if (i >= FTS_UPGRADE_LOOP) {
FTS_ERROR("[UPGRADE] read vendor id failed\n");
return -EIO;
}
return 0;
}
static int fts_ctpm_write_pram(struct i2c_client *client,
const char *pramfw_name)
{
int i_ret;
bool inrom = false;
const struct firmware *pramfw = NULL;
FTS_FUNC_ENTER();
i_ret = request_firmware(&pramfw, pramfw_name, &client->dev);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] Request firmware failed - %s (%d)\n",
pramfw_name, i_ret);
return i_ret;
}
/*check the length of the pramboot*/
if ((pramfw->size > APP_FILE_MAX_SIZE) ||
(pramfw->size < APP_FILE_MIN_SIZE)) {
FTS_ERROR("[UPGRADE] pramboot length(%zd) fail\n",
pramfw->size);
i_ret = -EINVAL;
goto write_pram_rel_fw;
}
/*send command to FW, reset and start write pramboot*/
i_ret = fts_ctpm_start_fw_upgrade(client);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] send upgrade cmd to FW error\n");
goto write_pram_rel_fw;
}
/*check run in rom or not! if run in rom, will write pramboot*/
inrom = fts_ctpm_check_run_state(client, FTS_RUN_IN_ROM);
if (!inrom) {
FTS_ERROR("[UPGRADE] not run in rom, write pramboot fail\n");
i_ret = -EIO;
goto write_pram_rel_fw;
}
/*write pramboot to pram*/
i_ret = fts_ctpm_write_pramboot_for_idc(client,
pramfw->size, pramfw->data);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] write pramboot fail\n");
goto write_pram_rel_fw;
}
/*read out checksum*/
i_ret = fts_ctpm_pramboot_ecc(client);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] write pramboot ecc error\n");
goto write_pram_rel_fw;
}
/*start pram*/
fts_ctpm_start_pramboot(client);
FTS_FUNC_EXIT();
write_pram_rel_fw:
release_firmware(pramfw);
return i_ret;
}
static int fts_ctpm_write_app(struct i2c_client *client,
const u8 *pbt_buf, u32 dw_length)
{
u32 temp;
int i_ret;
bool inpram = false;
FTS_FUNC_ENTER();
/*check run in pramboot or not if not rum in pramboot, can not upgrade*/
inpram = fts_ctpm_check_run_state(client, FTS_RUN_IN_PRAM);
if (!inpram) {
FTS_ERROR("[UPGRADE] not run in pram, upgrade fail\n");
return -EIO;
}
/*upgrade init*/
i_ret = fts_ctpm_upgrade_idc_init(client, dw_length);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] upgrade init error, upgrade fail\n");
return i_ret;
}
/*read vendor id from flash, if vendor id error, can not upgrade*/
i_ret = fts_ctpm_get_vendor_id_flash(client);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] read vendor id in flash fail\n");
return i_ret;
}
/*erase the app erea in flash*/
i_ret = fts_ctpm_erase_flash(client);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] erase flash error\n");
return i_ret;
}
/*start to write app*/
i_ret = fts_ctpm_write_app_for_idc(client, dw_length, pbt_buf);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] write app error\n");
return i_ret;
}
/*read check sum*/
temp = 0x1000;
i_ret = fts_ctpm_upgrade_ecc(client, temp, dw_length);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] ecc error\n");
return i_ret;
}
FTS_FUNC_EXIT();
return 0;
}
static int fts_ctpm_fw_upgrade_use_buf(struct i2c_client *client,
const u8 *pbt_buf, u32 fwsize)
{
int i_ret = 0;
FTS_FUNC_ENTER();
FTS_DEBUG("[UPGRADE] pramboot\n");
i_ret = fts_ctpm_write_pram(client, FT8716_PRAMBOOT_FW_NAME);
if (i_ret != 0) {
FTS_ERROR("[UPGRADE] write pram failed\n");
return -EIO;
}
i_ret = fts_ctpm_write_app(client, pbt_buf, fwsize);
FTS_FUNC_EXIT();
return i_ret;
}
static int fts_ctpm_check_vendor_id(struct i2c_client *client,
const u8 *data)
{
u8 vendor_id;
fts_i2c_read_reg(client, FTS_REG_VENDOR_ID, &vendor_id);
if ((vendor_id != 0x8D) &&
(data[APP_FILE_VENDORID_MAPPING] != vendor_id)) {
FTS_ERROR("[UPGRADE] vendor id(%02x)[%02x] is error\n",
data[APP_FILE_VENDORID_MAPPING], vendor_id);
return -EINVAL;
}
return 0;
}
static int fts_ctpm_check_chip_id(const u8 *data)
{
if ((data[APP_FILE_CHIPID_MAPPING] !=
fts_chip_type_8716.pramboot_idh) ||
(data[APP_FILE_CHIPID_MAPPING + 1] !=
fts_chip_type_8716.pramboot_idl)) {
FTS_ERROR("[UPGRADE] chip id(%02X%02X)[%02X%02X] is error\n",
data[APP_FILE_CHIPID_MAPPING],
data[APP_FILE_CHIPID_MAPPING + 1],
fts_chip_type_8716.pramboot_idh,
fts_chip_type_8716.pramboot_idl);
return -EINVAL;
}
return 0;
}
static bool fts_ctpm_check_app_bin_valid(const u8 *pbt_buf)
{
u32 len;
if (pbt_buf[0] != 0x02) {
FTS_ERROR("[UPGRADE] APP.BIN Verify the first byte(%x) error\n",
pbt_buf[0]);
return -EINVAL;
}
if (!fts_ecc_check(pbt_buf, APP1_START, APP1_LEN, APP1_ECC_ADDR)) {
FTS_ERROR("[UPGRADE] APP.BIN Verify- ecc1 error\n");
return -EINVAL;
}
if ((fts_data_word(pbt_buf, APP_VERIF_ADDR + APP_LEN) +
fts_data_word(pbt_buf, APP_VERIF_ADDR + APP_LEN_NE)) !=
0xFFFF) {
FTS_ERROR("[UPGRADE] APP.BIN Verify- Length XOR error\n");
return -EINVAL;
}
len = fts_data_word(pbt_buf, APP_VERIF_ADDR + APP_LEN);
FTS_DEBUG("%x %x %x %x", APP2_START, len,
((u32)fts_data_word(pbt_buf, APP_VERIF_ADDR + APP_LEN_H) << 16),
fts_data_word(pbt_buf, APP_VERIF_ADDR + APP_LEN));
len -= APP2_START;
if (!fts_ecc_check(pbt_buf, APP2_START, len, APP2_ECC_ADDR)) {
FTS_ERROR("[UPGRADE] APP.BIN Verify- ecc2 error\n");
return -EINVAL;
}
return 0;
}
static int fts_ctpm_fw_upgrade_with_app_bin_file
(struct i2c_client *client, const char *firmware_name)
{
int i_ret = 0;
const struct firmware *fw = NULL;
FTS_INFO("[UPGRADE] start upgrade with app.bin\n");
i_ret = request_firmware(&fw, firmware_name, &client->dev);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] Request firmware failed - %s (%d)\n",
firmware_name, i_ret);
return i_ret;
}
if (fw->size < APP_FILE_MIN_SIZE || fw->size > APP_FILE_MAX_SIZE) {
FTS_ERROR("[UPGRADE] FW length(%zd) error\n", fw->size);
i_ret = -EINVAL;
goto file_upgrade_rel_fw;
}
i_ret = fts_ctpm_check_vendor_id(client, fw->data);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] check vendor id failed\n");
goto file_upgrade_rel_fw;
}
i_ret = fts_ctpm_check_chip_id(fw->data);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] check chip id failed\n");
goto file_upgrade_rel_fw;
}
i_ret = fts_ctpm_check_app_bin_valid(fw->data);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] app.bin ecc failed\n");
goto file_upgrade_rel_fw;
}
i_ret = fts_ctpm_fw_upgrade_use_buf(client, fw->data, fw->size);
if (i_ret < 0) {
FTS_ERROR("[UPGRADE] upgrade app.bin failed\n");
goto file_upgrade_rel_fw;
}
file_upgrade_rel_fw:
release_firmware(fw);
return i_ret;
}

View file

@ -0,0 +1,410 @@
/*
*
* FocalTech fts TouchScreen driver.
*
* Copyright (c) 2010-2016, 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.
*
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/input/focaltech_mmi_modules.h>
#include "focaltech_flash.h"
#include "focaltech_upgrade_common.h"
static u8 upgrade_ecc;
int fts_ctpm_upgrade_idc_init(struct i2c_client *client, u32 dw_length)
{
int i_ret = 0;
u8 reg_val_id[4] = {0};
u8 auc_i2c_write_buf[10];
FTS_INFO("[UPGRADE] Upgrade setting Init\n");
/*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;
if (dw_length == 0)
return -EIO;
/*check the fw length by flash type*/
if (0x81 == (int)reg_val_id[0]) {
if (dw_length > 1024 * 60)
return -EIO;
} else if (0x80 == (int)reg_val_id[0]) {
if (dw_length > 1024 * 64)
return -EIO;
}
/*set flash clk*/
auc_i2c_write_buf[0] = 0x05;
auc_i2c_write_buf[1] = reg_val_id[0];
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;
}
void fts_ctpm_start_pramboot(struct i2c_client *client)
{
u8 auc_i2c_write_buf[10];
FTS_INFO("[UPGRADE] start pramboot\n");
auc_i2c_write_buf[0] = 0x08;
fts_i2c_write(client, auc_i2c_write_buf, 1);
msleep(20);
}
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\n");
i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_AA);
msleep(20);
i_ret = fts_i2c_write_reg(client, FTS_RST_CMD_REG1, FTS_UPGRADE_55);
msleep(200);
return i_ret;
}
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\n", cstate);
if (cstate == rstate)
return true;
msleep(20);
}
return false;
}
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\n");
auc_i2c_write_buf[0] = 0xcc;
fts_i2c_read(client, auc_i2c_write_buf, 1, reg_val, 1);
/*pramboot checksum != host checksum, upgrade fail*/
if (reg_val[0] != upgrade_ecc) {
FTS_ERROR("[UPGRADE] checksum fail pramboot=%x, host=%x\n",
reg_val[0], upgrade_ecc);
return -EIO;
}
FTS_DEBUG("[UPGRADE] checksum success pramboot=%x, host=%x\n",
reg_val[0], upgrade_ecc);
msleep(100);
FTS_FUNC_EXIT();
return 0;
}
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\n");
/*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(20);
}
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(20);
}
}
/*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\n",
reg_val[0], upgrade_ecc);
return -EIO;
}
FTS_DEBUG("[UPGRADE] ecc success : FW=%02x upgrade_ecc=%02x\n",
reg_val[0], upgrade_ecc);
upgrade_ecc = 0;
return i_ret;
}
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\n");
/*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);
/*erase flash success*/
if (0xF0 == reg_val[0] && 0xAA == reg_val[1])
break;
msleep(50);
}
/*erase flash fail*/
if ((0xF0 != reg_val[0] || 0xAA != reg_val[1]) && (i >= 15)) {
FTS_ERROR("[UPGRADE] erase app error.reset tp and reload FW\n");
return -EIO;
}
FTS_DEBUG("[UPGRADE] erase app ok\n");
return 0;
}
int fts_ctpm_write_pramboot_for_idc(struct i2c_client *client,
u32 length, const 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\n");
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;
}
int fts_ctpm_write_app_for_idc(struct i2c_client *client,
u32 length, const 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\n");
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 write 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(20);
}
}
msleep(50);
return 0;
}
#define AL2_FCS_COEF ((1 << 15) + (1 << 10) + (1 << 3))
static u16 fts_crc_calc(const u8 *pbt_buf, u32 addr, u16 length)
{
u16 cFcs = 0;
u16 i, j;
FTS_DEBUG("[UPGRADE][ECC] %04x data:%04x, len:%04x\n",
(addr), fts_data_word(pbt_buf, (addr)), length);
for (i = 0; i < length; i++) {
cFcs ^= fts_data_word(pbt_buf, (addr + i * 2));
for (j = 0; j < 16; j++) {
if (cFcs & 1)
cFcs = (u16)((cFcs >> 1) ^ AL2_FCS_COEF);
else
cFcs >>= 1;
}
}
return cFcs;
}
bool fts_ecc_check(const u8 *pbt_buf, u32 star_addr, u32 len, u16 ecc_addr)
{
u16 ecc1;
u16 ecc2;
u16 cal_ecc;
ecc1 = fts_data_word(pbt_buf, ecc_addr);
ecc2 = fts_data_word(pbt_buf, ecc_addr + 2);
if ((ecc1 + ecc2) != 0xFFFF)
return false;
cal_ecc = fts_crc_calc(pbt_buf, star_addr, (len / 2));
FTS_DEBUG("[UPGRADE][ECC] ecc1 = %x, cal_ecc = %x\n", ecc1, cal_ecc);
if (ecc1 != cal_ecc) {
FTS_DEBUG("[UPGRADE][ECC] ecc error\n");
return false;
}
return true;
}

View file

@ -0,0 +1,80 @@
/*
*
* FocalTech mmi TouchScreen driver header file.
*
* Copyright (c) 2010 Focal tech Ltd.
* Copyright (c) 2012-2016, The Linux Foundation. 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.
*
*/
#ifndef __LINUX_FOCALTECH_MMI_MODULES_H__
#define __LINUX_FOCALTECH_MMI_MODULES_H__
#define FT5X06_ID 0x55
#define FT5X16_ID 0x0A
#define FT5X36_ID 0x14
#define FT6X06_ID 0x06
#define FT6X36_ID 0x36
#define FT8716_ID 0x87
#define FT5X46_ID 0x54
#define FT8006U_ID 0xF0
#define MAX_PANEL_SUPPLIERS 5
struct fw_upgrade_info {
bool auto_cal;
u16 delay_aa;
u16 delay_55;
u8 upgrade_id_1;
u8 upgrade_id_2;
u16 delay_readid;
u16 delay_erase_flash;
};
struct ft_ts_platform_data {
struct fw_upgrade_info info;
const char *name;
const char *fw_name;
u32 irqflags;
u32 irq_gpio;
u32 irq_gpio_flags;
u32 reset_gpio;
u32 reset_gpio_flags;
u32 family_id;
u32 x_max;
u32 y_max;
u32 x_min;
u32 y_min;
u32 panel_minx;
u32 panel_miny;
u32 panel_maxx;
u32 panel_maxy;
u32 group_id;
u32 hard_rst_dly;
u32 soft_rst_dly;
u32 num_max_touches;
bool fw_vkey_support;
bool fw_update_mmi;
bool no_force_update;
bool i2c_pull_up;
bool ignore_id_check;
bool gesture_support;
bool resume_in_workqueue;
bool x_flip;
bool y_flip;
int (*power_init)(bool);
int (*power_on)(bool);
u32 num_vendor_ids;
u32 vendor_ids[MAX_PANEL_SUPPLIERS];
const char *vendor_names[MAX_PANEL_SUPPLIERS];
};
#endif