/*
* Goodix GT9xx touchscreen driver
*
* Copyright (C) 2010 - 2014 Goodix. Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be a reference
* to you, when you are integrating the GOODiX's CTP IC into your system,
* 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.
*
* Version: 2.4
* Release Date: 2014/11/28
*/
#include <linux/kthread.h>
#include "gt9xx.h"
#include <linux/namei.h>
#include <linux/mount.h>
#if ((GTP_AUTO_UPDATE && GTP_HEADER_FW_UPDATE) || GTP_COMPATIBLE_MODE)
#include "gt9xx_firmware.h"
#endif
#define GUP_REG_HW_INFO 0x4220
#define GUP_REG_FW_MSG 0x41E4
#define GUP_REG_PID_VID 0x8140
#define GUP_SEARCH_FILE_TIMES 50
#define UPDATE_FILE_PATH_1 "/data/_goodix_update_.bin"
#define UPDATE_FILE_PATH_2 "/sdcard/_goodix_update_.bin"
#define CONFIG_FILE_PATH_1 "/data/_goodix_config_.cfg"
#define CONFIG_FILE_PATH_2 "/sdcard/_goodix_config_.cfg"
#define FW_HEAD_LENGTH 14
#define FW_SECTION_LENGTH 0x2000 // 8K
#define FW_DSP_ISP_LENGTH 0x1000 // 4K
#define FW_DSP_LENGTH 0x1000 // 4K
#define FW_BOOT_LENGTH 0x800 // 2K
#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) // 32K
#define FW_BOOT_ISP_LENGTH 0x800 // 2k
#define FW_GLINK_LENGTH 0x3000 // 12k
#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) // 32k
#define PACK_SIZE 256
#define MAX_FRAME_CHECK_TIME 5
#define _bRW_MISCTL__SRAM_BANK 0x4048
#define _bRW_MISCTL__MEM_CD_EN 0x4049
#define _bRW_MISCTL__CACHE_EN 0x404B
#define _bRW_MISCTL__TMR0_EN 0x40B0
#define _rRW_MISCTL__SWRST_B0_ 0x4180
#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190
#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218
#define _rRW_MISCTL__BOOT_CTL_ 0x5094
#define AUTO_SEARCH_BIN 0x01
#define AUTO_SEARCH_CFG 0x02
#define BIN_FILE_READY 0x80
#define CFG_FILE_READY 0x08
#define HEADER_FW_READY 0x00
#pragma pack(1)
typedef struct
{
u8 hw_info[4]; //hardware info//
u8 pid[8]; //product id //
u16 vid; //version id //
}st_fw_head;
#pragma pack()
typedef struct
{
u8 force_update;
u8 fw_flag;
struct file *file;
struct file *cfg_file;
st_fw_head ic_fw_msg;
mm_segment_t old_fs;
u32 fw_total_len;
u32 fw_burned_len;
}st_update_msg;
st_update_msg update_msg;
u16 show_len;
u16 total_len;
u8 got_file_flag = 0;
u8 searching_file = 0;
extern u8 config[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
extern s32 gtp_send_cfg(struct i2c_client *client);
extern s32 gtp_read_version(struct i2c_client *, u16* );
extern struct i2c_client * i2c_connect_client;
extern void gtp_irq_enable(struct goodix_ts_data *ts);
extern void gtp_irq_disable(struct goodix_ts_data *ts);
extern s32 gtp_i2c_read_dbl_check(struct i2c_client *, u16, u8 *, int);
static u8 gup_burn_fw_gwake_section(struct i2c_client *client, u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd );
#define _CLOSE_FILE(p_file) if (p_file && !IS_ERR(p_file)) \
{ \
filp_close(p_file, NULL); \
}
#if GTP_ESD_PROTECT
extern void gtp_esd_switch(struct i2c_client *, s32);
#endif
#if GTP_COMPATIBLE_MODE
s32 gup_fw_download_proc(void *dir, u8 dwn_mode);
#endif
/*******************************************************
Function:
Read data from the i2c slave device.
Input:
client: i2c device.
buf[0~1]: read start address.
buf[2~len-1]: read data buffer.
len: GTP_ADDR_LENGTH + read bytes count
Output:
numbers of i2c_msgs to transfer:
2: succeed, otherwise: failed
*********************************************************/
s32 gup_i2c_read(struct i2c_client *client, u8 *buf, s32 len)
{
struct i2c_msg msgs[2];
s32 ret=-1;
s32 retries = 0;
GTP_DEBUG_FUNC();
msgs[0].flags = !I2C_M_RD;
msgs[0].addr = client->addr;
msgs[0].len = GTP_ADDR_LENGTH;
msgs[0].buf = &buf[0];
#ifdef CONFIG_I2C_ROCKCHIP_COMPAT
msgs[0].scl_rate=200 * 1000;
//msgs[0].scl_rate = 300 * 1000; // for Rockchip, etc
#endif
msgs[1].flags = I2C_M_RD;
msgs[1].addr = client->addr;
msgs[1].len = len - GTP_ADDR_LENGTH;
msgs[1].buf = &buf[GTP_ADDR_LENGTH];
#ifdef CONFIG_I2C_ROCKCHIP_COMPAT
msgs[1].scl_rate=200 * 1000;
//msgs[1].scl_rate = 300 * 1000; // for Rockchip, etc.
#endif
while(retries < 5)
{
ret = i2c_transfer(client->adapter, msgs, 2);
if(ret == 2)break;
retries++;
}
return ret;
}
/*******************************************************
Function:
Write data to the i2c slave device.
Input:
client: i2c device.
buf[0~1]: write start address.
buf[2~len-1]: data buffer
len: GTP_ADDR_LENGTH + write bytes count
Output:
numbers of i2c_msgs to transfer:
1: succeed, otherwise: failed
*********************************************************/
s32 gup_i2c_write(struct i2c_client *client,u8 *buf,s32 len)
{
struct i2c_msg msg;
s32 ret=-1;
s32 retries = 0;
GTP_DEBUG_FUNC();
msg.flags = !I2C_M_RD;
msg.addr = client->addr;
msg.len = len;
msg.buf = buf;
#ifdef CONFIG_I2C_ROCKCHIP_COMPAT
msg.scl_rate=200 * 1000;
//msg.scl_rate = 300 * 1000; // for Rockchip, etc
#endif
while(retries < 5)
{
ret = i2c_transfer(client->adapter, &msg, 1);
if (ret == 1)break;
retries++;
}
return ret;
}
static s32 gup_init_panel(struct goodix_ts_data *ts)
{
s32 ret = 0;
s32 i = 0;
u8 check_sum = 0;
u8 opr_buf[16];
u8 sensor_id = 0;
u16 version = 0;
u8 drv_cfg_version;
u8 flash_cfg_version;
#ifndef GTP_CONFIG_OF
u8 cfg_info_group0[] = CTP_CFG_GROUP0;
u8 cfg_info_group1[] = CTP_CFG_GROUP1;
u8 cfg_info_group2[] = CTP_CFG_GROUP2;
u8 cfg_info_group3[] = CTP_CFG_GROUP3;
u8 cfg_info_group4[] = CTP_CFG_GROUP4;
u8 cfg_info_group5[] = CTP_CFG_GROUP5;
u8 *send_cfg_buf[] = {cfg_info_group0,cfg_info_group1,
cfg_info_group2, cfg_info_group3,
cfg_info_group4, cfg_info_group5};
u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0),
CFG_GROUP_LEN(cfg_info_group1),
CFG_GROUP_LEN(cfg_info_group2),
CFG_GROUP_LEN(cfg_info_group3),
CFG_GROUP_LEN(cfg_info_group4),
CFG_GROUP_LEN(cfg_info_group5)};
#endif
ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, &sensor_id, 1);
if (SUCCESS == ret)
{
if (sensor_id >= 0x06)
{
GTP_ERROR("Invalid sensor_id(0x%02X), No Config Sent!", sensor_id);
return -1;
}
}
else
{
GTP_ERROR("Failed to get sensor_id, No config sent!");
return -1;
}
/* parse config data*/
#ifdef GTP_CONFIG_OF
GTP_DEBUG("Get config data from dts file.");
ret = gtp_parse_dt_cfg(&ts->client->dev, &config[GTP_ADDR_LENGTH], &ts->gtp_cfg_len, sensor_id);
if (ret < 0) {
GTP_ERROR("Failed to parse config data form dts file.");
ts->pnl_init_error = 1;
return -1;
}
#else
GTP_DEBUG("Get config data from h