blob: b5a325823441496bbb577450573843801116c515 [file] [log] [blame]
/*
*
* 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;
}