goodix 五点触摸屏驱动源文件分析
2012-08-18 16:26
453 查看
驱动的目录结构如下:
.../build.sh
.../driver
.../driver/gt818.h
.../driver/gt818_update.h
.../driver/gt818.mod.c //编译时自动生成
.../driver/gt818.c //主要驱动文件
.../driver/Makefile
.../firmware
.../firmware/update_0080.bin //固件
.../init.3rdparty.rc
备注:头文件(gt818.h) 请查看如下链接,这两份都是完整的代码。gt818_update.h 对于使用来说没有什么用处,可以不用。
/article/1921593.html
头文件(gt818_update.h)请查看如下链接。 内容很简单,就是一个存储参数的数组。
http://blog.csdn.net/duanlove/article/details/11127833
--------------------------------------------- gt818.c -----------------------------------------------------------------------------
/* drivers/input/touchscreen/goodix_touch.c
*
* Copyright (C) 2011 Goodix, Inc.
*
* Author: Felix
* Date: 2011.04.28
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/earlysuspend.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <mach/gpio.h>
//#include <plat/gpio-cfg.h>
//#include <plat/gpio-bank-l.h>
//#include <plat/gpio-bank-f.h>
#include <linux/irq.h>
#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <linux/proc_fs.h>
#include "gt818.h"//<linux/gt818.h>
#include "gt818_update.h"//<linux/gt818_50.h>
//#include <linux/goodix_queue.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/completion.h>
#include <asm/uaccess.h>
#include <mach/ldo.h>
#include <mach/regs_ana.h>
#if !defined(GT801_PLUS) && !defined(GT801_NUVOTON)
#error The code does not match this touchscreen.
#endif
static struct workqueue_struct *goodix_wq;
static const char *s3c_ts_name = "pixcir_ts";
//static struct point_queue finger_list;
struct i2c_client * i2c_connect_client = NULL;
//EXPORT_SYMBOL(i2c_connect_client);
static struct proc_dir_entry *goodix_proc_entry;
static short goodix_read_version(struct goodix_ts_data *ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
static int gt818_downloader( struct goodix_ts_data *ts, unsigned char * data,unsigned char * path );
#endif
//used by firmware update CRC
unsigned int oldcrc32 = 0xFFFFFFFF;
unsigned int crc32_table[256];
unsigned int ulPolynomial = 0x04c11db7;
//static int gt818_gpio_tp_irq=0;
//static int shout_down_num=0;
//static int int_cfg_num=0;
//static int ts_int=0;
static int gt818_gpio_tp_irq_int_num=0;
static int gt818_gpio_tp_rst = 59;
static int gt818_gpio_tp_irq = 60;
static int gt818_wrong_num =0;
#define TS_DEBUG_MSG 1
//#define I2C_BOARD_INFO_METHOD 0
//#define TS_DATA_THRESHOLD_CHECK 1
//#define TS_WIDTH_MAX 320
//#define TS_HEIGHT_MAX 480
//static int debug_level=0;
#if TS_DEBUG_MSG
#define TS_DBG(format, ...) \
printk(KERN_INFO "gt818 " format "\n", ## __VA_ARGS__)
#else
#define TS_DBG(format, ...)
#endif
static struct sprd_i2c_setup_data {
unsigned i2c_bus; //the same number as i2c->adap.nr in adapter probe function
unsigned short i2c_address;
int irq;
char type[I2C_NAME_SIZE];
};
static struct sprd_i2c_setup_data gt818_ts_setup={1, GT818_TS_ADDR, 0, GOODIX_I2C_NAME};
static int gt818_sprd_add_i2c_device(struct sprd_i2c_setup_data *i2c_set_data, struct i2c_driver *driver)
{
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client;
int ret,err;
TS_DBG("%s : i2c_bus=%d; slave_address=0x%x; i2c_name=%s",__func__,i2c_set_data->i2c_bus, \
i2c_set_data->i2c_address, i2c_set_data->type);
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = i2c_set_data->i2c_address;
strlcpy(info.type, i2c_set_data->type, I2C_NAME_SIZE);
if(i2c_set_data->irq > 0)
info.irq = i2c_set_data->irq;
adapter = i2c_get_adapter( i2c_set_data->i2c_bus);
if (!adapter) {
printk("%s: can't get i2c adapter %d\n",
__func__, i2c_set_data->i2c_bus);
err = -ENODEV;
goto err_driver;
}
client = i2c_new_device(adapter, &info);
if (!client) {
printk("%s: can't add i2c device at 0x%x\n",
__func__, (unsigned int)info.addr);
err = -ENODEV;
goto err_driver;
}
i2c_put_adapter(adapter);
ret = i2c_add_driver(driver);
if (ret != 0) {
printk("%s: can't add i2c driver\n", __func__);
err = -ENODEV;
goto err_driver;
}
return 0;
err_driver:
return err;
}
static void gt818_sprd_del_i2c_device(struct i2c_client *client, struct i2c_driver *driver)
{
TS_DBG("%s : slave_address=0x%x; i2c_name=%s",__func__, client->addr, client->name);
i2c_unregister_device(client);
i2c_del_driver(driver);
}
//static struct sprd_i2c_setup_data ft5x0x_ts_setup={0, FT5206_TS_ADDR_R, 0, FT5206_TS_NAME};
/*******************************************************************************
* Function : ft5x0x_ts_config_pins
* Description : config gpio pins and set relative TS pins
* Parameters : void
* Return : int irq_num;
*******************************************************************************/
static int gt818_config_pins(void)
{
int gt818irq;
gpio_direction_output(gt818_gpio_tp_rst, 1);
gpio_direction_input(gt818_gpio_tp_irq);
gpio_set_value(gt818_gpio_tp_rst, 1);
gt818irq=sprd_alloc_gpio_irq(gt818_gpio_tp_irq);
msleep(10); //wait for stable
return gt818irq;
}
/*******************************************************
鍔熻兘锛?
璇诲彇浠庢満鏁版嵁
姣忎釜璇绘搷浣滅敤涓ゆ潯i2c_msg缁勬垚锛岀1鏉℃秷鎭敤浜庡彂閫佷粠鏈哄湴鍧€锛? 绗?鏉$敤浜庡彂閫佽鍙栧湴鍧€鍜屽彇鍥炴暟鎹紱姣忔潯娑堟伅鍓嶅彂閫佽捣濮嬩俊鍙?鍙傛暟锛? client: i2c璁惧锛屽寘鍚澶囧湴鍧€
buf[0]锛?棣栧瓧鑺備负璇诲彇鍦板潃
buf[1]~buf[len]锛氭暟鎹紦鍐插尯
len锛?璇诲彇鏁版嵁闀垮害
return锛? 鎵ц娑堟伅鏁?*********************************************************/
/*Function as i2c_master_send */
static int i2c_read_bytes(struct i2c_client *client, uint8_t *buf, int len)
{
struct i2c_msg msgs[2];
int ret=-1;
//鍙戦€佸啓鍦板潃
msgs[0].flags=!I2C_M_RD;//鍐欐秷鎭? msgs[0].addr=client->addr;
msgs[0].len=2;
msgs[0].buf=&buf[0];
//鎺ユ敹鏁版嵁
msgs[1].flags=I2C_M_RD;//璇绘秷鎭? msgs[1].addr=client->addr;
msgs[1].len=len-2;
msgs[1].buf=&buf[2];
ret=i2c_transfer(client->adapter,msgs, 2);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍚戜粠鏈哄啓鏁版嵁
鍙傛暟锛? client: i2c璁惧锛屽寘鍚澶囧湴鍧€
buf[0]锛?棣栧瓧鑺備负鍐欏湴鍧€
buf[1]~buf[len]锛氭暟鎹紦鍐插尯
len锛?鏁版嵁闀垮害
return锛? 鎵ц娑堟伅鏁?*******************************************************/
/*Function as i2c_master_send */
static int i2c_write_bytes(struct i2c_client *client,uint8_t *data,int len)
{
struct i2c_msg msg;
int ret=-1;
//鍙戦€佽澶囧湴鍧€
msg.flags=!I2C_M_RD;//鍐欐秷鎭? msg.addr=client->addr;
msg.len=len;
msg.buf=data;
ret=i2c_transfer(client->adapter,&msg, 1);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍙戦€佸墠缂€鍛戒护
ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛?
鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int i2c_pre_cmd(struct goodix_ts_data *ts)
{
int ret;
uint8_t pre_cmd_data[2]={0};
pre_cmd_data[0]=0x0f;
pre_cmd_data[1]=0xff;
ret=i2c_write_bytes(ts->client,pre_cmd_data,2);
//msleep(2);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍙戦€佸悗缂€鍛戒护
ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛?
鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int i2c_end_cmd(struct goodix_ts_data *ts)
{
int ret;
uint8_t end_cmd_data[2]={0};
end_cmd_data[0]=0x80;
end_cmd_data[1]=0x00;
ret=i2c_write_bytes(ts->client,end_cmd_data,2);
//msleep(2);
return ret;
}
/*
*/
static short get_chip_version( unsigned int sw_ver )
{
if ( (sw_ver&0xff) < TPD_CHIP_VERSION_C_FIRMWARE_BASE )
return TPD_GT818_VERSION_B;
else if ( (sw_ver&0xff) < TPD_CHIP_VERSION_D_FIRMWARE_BASE )
return TPD_GT818_VERSION_C;
else
return TPD_GT818_VERSION_D;
}
/*******************************************************
鍔熻兘锛? Guitar鍒濆鍖栧嚱鏁帮紝鐢ㄤ簬鍙戦€侀厤缃俊鎭紝鑾峰彇鐗堟湰淇℃伅
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int goodix_init_panel(struct goodix_ts_data *ts)
{
short ret=-1;
// int ic_size = 0;
#if 1
uint8_t config_info_c[] = { //Touch key devlop board
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x01,0x13,0x80,0x88,0x90,0x14,
0x15,0x40,0x0F,0x0F,0x0A,0x50,0x3C,0x0C,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
};
uint8_t config_info_d[] = { //Touch key devlop board
#if 0
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x0B,0x13,0x90,0x90,0x90,0x27,
0x27,0x27,0x0F,0x0F,0x0A,0x50,0x3C,0x4B,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x05,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
/*0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x01,0x13,0x80,0x88,0x90,0x14,
0x15,0x40,0x0F,0x0F,0x0A,0x50,0x3C,0x0C,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
*/
#endif
#if 1 //defined(CONFIG_S9_IPhone) //s9 hua fei jeed
/*0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x02,0x22,0x12,0x22,0x22,0x22,
0x32,0x22,0x42,0x22,0x52,0x22,0x62,0x22,
0xE2,0x22,0xD2,0x22,0xC2,0x22,0xB2,0x22,
0xA2,0x22,0x92,0x22,0x82,0x22,0x72,0x22,
0xF2,0x22,0x37,0x03,0xA8,0xA8,0xA8,0x1A,
0x1A,0x1A,0x0F,0x0E,0x0A,0x48,0x38,0x09,
//0x03,0x00,0x05,0x40,0x01,0xE0,0x01,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x57,0x60,0x5A,0x00,0x00,0x23,
0x14,0x05,0x05,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0xCE,0x03,0x00,0x40,0x37,0x10,
0x31,0x00,0x40,0x50,0x60,0x70,0x0D,0x40,
0x30,0x25,0x20,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
/*0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x60,0x00,0x50,0x00,0x40,0x00,
0x30,0x00,0x20,0x00,0x10,0x00,0x00,0x00,
0xF0,0x00,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x1B,0x03,0x70,0x70,0x70,0x26,
0x26,0x26,0x10,0x0F,0x0A,0x50,0x30,0x45,
//0x03,0x16,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x55,0x4F,0x58,0x52,0x00,0x00,0x03,
0x14,0x05,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x40,0x37,0x50,
0x26,0x00,0x10,0x20,0x00,0x00,0x0D,0x40,
0x30,0x3C,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
/*
0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0xF0,0x00,0xE0,0x00,0xD0,0x00,
0xC0,0x00,0xB0,0x00,0xA0,0x00,0x90,0x00,
0x80,0x00,0x1B,0x03,0x70,0x70,0x70,0x27,
0x27,0x27,0x10,0x0F,0x0A,0x50,0x30,0x0D,
//0x03,0x16,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x55,0x4F,0x58,0x52,0x00,0x00,0x03,
0x14,0x05,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x40,0x37,0x30,
0x26,0x00,0x70,0x80,0x90,0xA0,0x0D,0x40,
0x30,0x3C,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x70,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x3B,0x13,0x10,0x10,0x10,0x1E,
0x1E,0x1E,0x10,0x0F,0x0A,0x5A,0x4A,0x4F,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x50,0x49,0x54,0x4C,0x00,0x00,0x1B,
0x14,0x05,0x0A,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x31,0x03,0x00,0x40,0x3B,0x10,
0x21,0x00,0x70,0x80,0x90,0xA0,0x0B,0x50,
0x40,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#elif 0 //defined(CONFIG_S1_IPhone) // s1 lce
0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0x07,0x03,0x10,0x10,0x10,0x24,
0x24,0x24,0x10,0x0F,0x0A,0x40,0x30,0x0D,
//0x03,0x00,0x05,0x00,0x14,0x00,0x1E,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5A,0x5D,0x5E,0x61,0x00,0x00,0x03,
0x14,0x00,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0xEF,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x22,0x45,0x6C,0x92,0x0D,0x40,
0x30,0x25,0x20,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#elif 0 //s9 hua fei soeya
/*0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x81,0x11,0x91,0x11,0xA1,0x11,
0xB1,0x11,0xC1,0x11,0xD1,0x11,0xE1,0x11,
0x71,0x11,0x61,0x11,0x51,0x11,0x41,0x11,
0x31,0x11,0x21,0x11,0x11,0x11,0x01,0x11,
0xF1,0x11,0x07,0x03,0x10,0x10,0x10,0x25,
0x25,0x25,0x0F,0x0E,0x0A,0x40,0x30,0x09,
//0x03,0x00,0x05,0x40,0x01,0xE0,0x01,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x4F,0x60,0x53,0x00,0x00,0x02,
0x14,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x30,0x37,0x10,
0x28,0x00,0x40,0x72,0x61,0x50,0x0F,0x35,
0x25,0x25,0x1A,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
*/
#else
0x06,0xA2, // lce jeed
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x17,0x13,0xE8,0xE8,0xE8,0x1C,
0x1C,0x1C,0x10,0x0F,0x0A,0x50,0x40,0x09,
//0x03,0x00,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x5C,0x60,0x60,0x00,0x00,0x23,
0x14,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x06,0x04,0x00,0x40,0x17,0x10,
0x1E,0x00,0x30,0x40,0x50,0x60,0x0A,0x50,
0x40,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#endif
};
#endif
ret = goodix_read_version(ts);
if (ret < 0)
return ret;
dev_info(&ts->client->dev," Guitar Version: %d\n",ts->version);
if((ts->version&0xff) < TPD_CHIP_VERSION_D_FIRMWARE_BASE)
{
dev_info(&ts->client->dev," Guitar Version: C\n");
config_info_c[57] = (config_info_c[57]&0xf7)|(INT_TRIGGER<<3);
ret=i2c_write_bytes(ts->client,config_info_c, (sizeof(config_info_c)/sizeof(config_info_c[0])));
}
else
{
dev_info(&ts->client->dev," Guitar Version: D\n");
config_info_d[57] = (config_info_d[57]&0xf7)|(INT_TRIGGER<<3);
ret=i2c_write_bytes(ts->client,config_info_d, (sizeof(config_info_d)/sizeof(config_info_d[0])));
}
if (ret < 0)
return ret;
msleep(10);
return 0;
}
/*******************************************************
鍔熻兘锛? 鑾峰彇鐗堟湰淇℃伅
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static short goodix_read_version(struct goodix_ts_data *ts)
{
short ret;
uint8_t version_data[5]={0}; //store touchscreen version infomation
memset(version_data, 0, 5);
version_data[0]=0x07;
version_data[1]=0x17;
msleep(5);
//ret=i2c_read_bytes(ts->client, version_data, 4);
//msleep(2);
ret=i2c_read_bytes(ts->client, version_data, 4);
if (ret < 0)
return ret;
dev_info(&ts->client->dev," Guitar Version: %d.%d\n",version_data[3],version_data[2]);
ts->version = (version_data[3]<<8)+version_data[2];
return ret;
}
/*******************************************************
鍔熻兘锛? 瑙︽懜灞忓伐浣滃嚱鏁? 鐢变腑鏂Е鍙戯紝鎺ュ彈1缁勫潗鏍囨暟鎹紝鏍¢獙鍚庡啀鍒嗘瀽杈撳嚭
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{
uint8_t touch_data[3] = {READ_TOUCH_ADDR_H,READ_TOUCH_ADDR_L,0};
uint8_t key_data[3] ={READ_KEY_ADDR_H,READ_KEY_ADDR_L,0};
uint8_t point_data[8*MAX_FINGER_NUM+2]={ 0 };
static uint8_t finger_last[MAX_FINGER_NUM+1]={0}; //涓婃瑙︽懜鎸夐敭鐨勬墜鎸囩储寮? uint8_t finger_current[MAX_FINGER_NUM+1] = {0}; //褰撳墠瑙︽懜鎸夐敭鐨勬墜鎸囩储寮? uint8_t coor_data[6*MAX_FINGER_NUM] = {0}; //瀵瑰簲鎵嬫寚鐨勬暟鎹? static uint8_t last_key = 0;
uint8_t finger = 0;
uint8_t key = 0;
unsigned int count = 0;
unsigned int position = 0;
int ret=-1;
int tmp = 0;
int temp = 0;
uint16_t *coor_point;
//printk("goodix \n");
struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
i2c_pre_cmd(ts);
#ifndef INT_PORT
COORDINATE_POLL:
#endif
if( tmp > 9) {
dev_info(&(ts->client->dev), "Because of transfer error,touchscreen stop working.\n");
goto XFER_ERROR ;
}
ret=i2c_read_bytes(ts->client, touch_data,sizeof(touch_data)/sizeof(touch_data[0])); //璇?x712锛岃Е鎽? if(ret <= 0) {
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
#ifdef H***E_TOUCH_KEY
ret=i2c_read_bytes(ts->client, key_data,sizeof(key_data)/sizeof(key_data[0])); //璇?x721锛屾寜閿?
if(ret <= 0) {
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
key = key_data[2]&0x0f;
#endif
if(ts->bad_data)
//TODO:Is sending config once again (to reset the chip) useful?
msleep(20);
#if 1
if(touch_data[2] == 0x0f)
{
printk("goodix 01=%x\n",touch_data[2]);
goodix_init_panel(ts);
goto DATA_NO_READY;
}
if((touch_data[2]&0x30)!=0x20)
{
printk("goodix 02=%x\n",touch_data[2]&0x30);
gt818_wrong_num++;
if(gt818_wrong_num>5)
{
gt818_wrong_num=0;
goodix_init_panel(ts);
}
goto DATA_NO_READY;
}
gt818_wrong_num=0;
#else
printk("goodix %x\n",touch_data[2]);
if((touch_data[2]&0x30)!=0x20)
{
printk("goodix 01=%x\n",touch_data[2]&0x30);
gt818_wrong_num++;
if(gt818_wrong_num>5)
{
gt818_wrong_num=0;
//goodix_init_panel(ts);
}
goto DATA_NO_READY;
}
gt818_wrong_num=0;
if((touch_data[2]&0x0f) == 0x0f)
{
printk("goodix 02=%x\n",touch_data[2]&0x0f);
goodix_init_panel(ts);
goto DATA_NO_READY;
}
#endif
ts->bad_data = 0;
finger = touch_data[2]&0x0f;
if(finger != 0)
{
point_data[0] = READ_COOR_ADDR_H; //read coor high address
point_data[1] = READ_COOR_ADDR_L; //read coor low address
ret=i2c_read_bytes(ts->client, point_data, finger*8+2);
if(ret <= 0)
{
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
for(position=2; position<((finger-1)*8+2+1); position += 8)
{
temp = point_data[position];
if(temp<(MAX_FINGER_NUM+1))
{
finger_current[temp] = 1;
for(count=0; count<6; count++)
{
coor_data[(temp-1)*6+count] = point_data[position+1+count]; //璁板綍褰撳墠鎵嬫寚绱㈠紩锛屽苟瑁呰浇鍧愭爣鏁版嵁
}
}
else
{
dev_err(&(ts->client->dev),"Track Id error:%d\n ",0);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
}
//coor_point = (uint16_t *)coor_data;
}
else
{
for(position=1;position < MAX_FINGER_NUM+1; position++)
{
finger_current[position] = 0;
}
}
coor_point = (uint16_t *)coor_data;
for(position=1;position < MAX_FINGER_NUM+1; position++)
{
if((finger_current[position] == 0)&&(finger_last[position] != 0))
{
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, 0);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
// input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
input_mt_sync(ts->input_dev);
//printk("report error\n");
}
else if(finger_current[position])
{
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, (*(coor_point+3*(position-1)))); //can change x-y!!!
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, (*(coor_point+3*(position-1)+1)));
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,1);
//input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, finger_list.pointer[0].pressure);
input_mt_sync(ts->input_dev);
// input_report_abs(ts->input_dev, ABS_X, finger_list.pointer[0].x);
// input_report_abs(ts->input_dev, ABS_Y, finger_list.pointer[0].y)
// input_report_abs(ts->input_dev, ABS_PRESSURE, finger_list.pointer[0].pressure);
// input_sync(ts->input_dev);
// printk("%d*",(*(coor_point+3*(position-1)))*SCREEN_MAX_HEIGHT/(TOUCH_MAX_HEIGHT));
// printk("%d*",(*(coor_point+3*(position-1)+1))*SCREEN_MAX_WIDTH/(TOUCH_MAX_WIDTH));
// printk("\n");
//printk("x=%d ",(*(coor_point+3*(position-1))));
//printk("y=%d ",(*(coor_point+3*(position-1)+1)));
printk("\n");
}
}
input_sync(ts->input_dev);
for(position=1;position<MAX_FINGER_NUM+1; position++)
{
finger_last[position] = finger_current[position];
}
#ifdef H***E_TOUCH_KEY
if((last_key == 0)&&(key == 0))
;
else
{
for(count = 0; count < 4; count++)
{
input_report_key(ts->input_dev, touch_key_array[count], !!(key&(0x01<<count)));
}
//printk("goodix key=%d \n",key);
}
last_key = key;
#endif
DATA_NO_READY:
XFER_ERROR:
i2c_end_cmd(ts);
if(ts->use_irq)
enable_irq(ts->client->irq);
}
/*******************************************************
鍔熻兘锛? 璁℃椂鍣ㄥ搷搴斿嚱鏁? 鐢辫鏃跺櫒瑙﹀彂锛岃皟搴﹁Е鎽稿睆宸ヤ綔鍑芥暟杩愯锛涗箣鍚庨噸鏂拌鏃?鍙傛暟锛? timer锛氬嚱鏁板叧鑱旂殑璁℃椂鍣?
return锛? 璁℃椂鍣ㄥ伐浣滄ā寮忥紝HRTIMER_NORESTART琛ㄧず涓嶉渶瑕佽嚜鍔ㄩ噸鍚?********************************************************/
static enum hrtimer_restart goodix_ts_timer_func(struct hrtimer *timer)
{
struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
queue_work(goodix_wq, &ts->work);
hrtimer_start(&ts->timer, ktime_set(0, (POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
/*******************************************************
鍔熻兘锛? 涓柇鍝嶅簲鍑芥暟
鐢变腑鏂Е鍙戯紝璋冨害瑙︽懜灞忓鐞嗗嚱鏁拌繍琛?鍙傛暟锛? timer锛氬嚱鏁板叧鑱旂殑璁℃椂鍣?
return锛? 璁℃椂鍣ㄥ伐浣滄ā寮忥紝HRTIMER_NORESTART琛ㄧず涓嶉渶瑕佽嚜鍔ㄩ噸鍚?********************************************************/
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
struct goodix_ts_data *ts = dev_id;
//printk(KERN_INFO"-------------------ts_irq_handler------------------\n");
disable_irq_nosync(ts->client->irq);
queue_work(goodix_wq, &ts->work);
return IRQ_HANDLED;
}
/*******************************************************
鍔熻兘锛? 绠$悊GT801鐨勭數婧愶紝鍏佽GT801 PLUS杩涘叆鐫$湢鎴栧皢鍏跺敜閱?鍙傛暟锛? on: 0琛ㄧず浣胯兘鐫$湢锛?涓哄敜閱?return锛? 鏄惁璁剧疆鎴愬姛锛?涓烘垚鍔? 閿欒鐮侊細-1涓篿2c閿欒锛?2涓篏PIO閿欒锛?EINVAL涓哄弬鏁皁n閿欒
********************************************************/
//#if defined(INT_PORT)
static int goodix_ts_power(struct goodix_ts_data * ts, int on)
{
int ret = -1;
int retry = 50;//zsf add
unsigned char i2c_control_buf[3] = {0x06,0x92,0x01}; //suspend cmd
#ifdef INT_PORT
if(ts != NULL && !ts->use_irq)
return -2;
#endif
switch(on)
{
case 0:
i2c_pre_cmd(ts); //must
ret = i2c_write_bytes(ts->client, i2c_control_buf, 3);
printk(KERN_INFO"Send suspend cmd\n");
if(ret > 0) //failed
ret = 0;
i2c_end_cmd(ts); //must
return ret;
case 1:
//zsf add start
sndpw_retry:
retry--;
//zsf add end
#if 0 // #ifdef INT_PORT //suggest use INT PORT to wake up !!!
gpio_direction_output(gt818_gpio_tp_irq, 0);
msleep(20);
gpio_direction_output(gt818_gpio_tp_irq, 1);
msleep(20);
gpio_direction_output(gt818_gpio_tp_irq, 0);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
//if(ts->use_irq)
// s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port as interrupt port
//else
gpio_direction_input(gt818_gpio_tp_irq);
#else
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
#endif
msleep(40);
ret = goodix_init_panel(ts);
if(ret < 0&& retry>0)//zsf add
goto sndpw_retry;
return ret;
default:
printk(KERN_DEBUG "%s: Cant't support this command.", s3c_ts_name);
return -EINVAL;
}
}
/*******************************************************
鍔熻兘锛? 瑙︽懜灞忔帰娴嬪嚱鏁? 鍦ㄦ敞鍐岄┍鍔ㄦ椂璋冪敤(瑕佹眰瀛樺湪瀵瑰簲鐨刢lient)锛? 鐢ㄤ簬IO,涓柇绛夎祫婧愮敵璇凤紱璁惧娉ㄥ唽锛涜Е鎽稿睆鍒濆鍖栫瓑宸ヤ綔
鍙傛暟锛? client锛氬緟椹卞姩鐨勮澶囩粨鏋勪綋
id锛氳澶嘔D
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//TODO:鍦ㄦ祴璇曞け璐ュ悗闇€瑕侀噴鏀総s
int ret = 0;
int retry=0;
//unsigned short version_temp = 0;
unsigned char update_path[1] = {0};
#if defined(NO_DEFAULT_ID) && defined(INT_PORT)
uint8_t goodix_id[3] = {0,0xff,0};
#endif
char test_data = 1;
struct goodix_ts_data *ts;
struct goodix_i2c_rmi_platform_data *pdata;
dev_dbg(&client->dev,"Install touch driver.\n");
//Check I2C function
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");
ret = -ENODEV;
goto err_check_functionality_failed;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
ret = -ENOMEM;
goto err_alloc_data_failed;
}
i2c_connect_client = client; //used by Guitar_Update
#ifdef INT_PORT
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
#endif
#if defined(NO_DEFAULT_ID) && defined(INT_PORT)
for(retry=0;retry < 3; retry++)
{
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(20);
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
break;
}
if(ret <= 0)
{
gpio_direction_output(gt818_gpio_tp_irq,0);
msleep(1);
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(20);
gpio_direction_input(gt818_gpio_tp_rst);
for(retry=0;retry < 80; retry++)
{
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
{
msleep(10);
ret =i2c_read_bytes(client, goodix_id, 3); //Test I2C connection.
if (ret > 0)
{
if(goodix_id[2] == 0x55)
{
gpio_direction_output(gt818_gpio_tp_irq,1);
msleep(1);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
msleep(10);
break;
}
}
}
}
}
#endif
//while(1)
for(retry=0;retry < 3; retry++)
{
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(20);
//gt818_ts_reset();
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
break;
}
if(ret <= 0)
{
dev_err(&client->dev, "Warnning: I2C communication might be ERROR ret=%d!\n", ret);
goto err_i2c_failed;
}
INIT_WORK(&ts->work, goodix_ts_work_func); //init work_struct
ts->client = client;
i2c_set_clientdata(client, ts);
pdata = client->dev.platform_data;
#ifdef AUTO_UPDATE_GT818
i2c_pre_cmd(ts);
goodix_read_version(ts);
i2c_end_cmd(ts);
ret = gt818_downloader( ts, goodix_gt818_firmware, update_path);
if(ret < 0)
{
dev_err(&client->dev, "Warnning: GT818 update might be ERROR!\n");
//goto err_input_dev_alloc_failed;
}
#endif
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
dev_dbg(&client->dev,"goodix_ts_probe: Failed to allocate input device\n");
goto err_input_dev_alloc_failed;
}
ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); // absolute coor (x,y)
#ifdef H***E_TOUCH_KEY
for(retry = 0; retry < MAX_KEY_NUM; retry++)
{
input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
}
#endif
input_set_abs_params(ts->input_dev, ABS_X, 0, TOUCH_MAX_WIDTH, 0, 0);
input_set_abs_params(ts->input_dev, ABS_Y, 0, TOUCH_MAX_HEIGHT, 0, 0);
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
#ifdef GOODIX_MULTI_TOUCH
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, TOUCH_MAX_WIDTH, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, TOUCH_MAX_HEIGHT, 0, 0);
#endif
sprintf(ts->phys, "input/ts");
ts->input_dev->name = s3c_ts_name;
ts->input_dev->phys = ts->phys;
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0xDEAD;
ts->input_dev->id.product = 0xBEEF;
ts->input_dev->id.version = 10427; //screen firmware version
ret = input_register_device(ts->input_dev);
if (ret) {
dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
goto err_input_register_device_failed;
}
ts->bad_data = 0;
// finger_list.length = 0;
#ifdef INT_PORT
client->irq=gt818_gpio_tp_irq_int_num; //If not defined in client
if (client->irq)
{
ret = gpio_request(gt818_gpio_tp_irq, "TS_INT"); //Request IO
if (ret < 0)
{
dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)gt818_gpio_tp_irq,ret);
goto err_gpio_request_failed;
}
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE); //ret > 0 ?
//s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port function
#if INT_TRIGGER==1
#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_RISING
#elif INT_TRIGGER==0
#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_FALLING
// #elif INT_TRIGGER==2
// #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_LOW
// #elif INT_TRIGGER==3
// #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_HIGH
#endif
ret = request_irq(client->irq, goodix_ts_irq_handler , GT801_PLUS_IRQ_TYPE,
client->name, ts);
if (ret != 0) {
dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret);
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
goto err_gpio_request_failed;
}
else
{
disable_irq(client->irq);
ts->use_irq = 1;
dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",gt818_gpio_tp_irq_int_num,gt818_gpio_tp_irq);
}
}
#endif
err_gpio_request_failed:
if (!ts->use_irq)
{
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = goodix_ts_timer_func;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
i2c_pre_cmd(ts);
msleep(2);
for(retry=0; retry<3; retry++)
{
ret=goodix_init_panel(ts);
dev_info(&client->dev,"the config ret is :%d\n",ret);
msleep(2);
if(ret != 0) //Initiall failed
continue;
else
break;
}
if(ret != 0) {
ts->bad_data=1;
goto err_init_godix_ts;
}
if(ts->use_irq)
enable_irq(client->irq);
ts->power = goodix_ts_power;
goodix_read_version(ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ts->early_suspend.suspend = goodix_ts_early_suspend;
ts->early_suspend.resume = goodix_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
goodix_proc_entry = create_proc_entry("goodix-update", 0666, NULL);
if(goodix_proc_entry == NULL)
{
dev_info(&client->dev, "Couldn't create proc entry!\n");
ret = -ENOMEM;
goto err_create_proc_entry;
}
else
{
dev_info(&client->dev, "Create proc entry success!\n");
goodix_proc_entry->write_proc = goodix_update_write;
goodix_proc_entry->read_proc = goodix_update_read;
//goodix_proc_entry->owner =THIS_MODULE;
}
#endif
i2c_end_cmd(ts);
dev_info(&client->dev,"Start %s in %s mode\n",
ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
return 0;
err_init_godix_ts:
i2c_end_cmd(ts);
if(ts->use_irq)
{
ts->use_irq = 0;
free_irq(client->irq,ts);
#ifdef INT_PORT
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
#endif
}
else
hrtimer_cancel(&ts->timer);
err_input_register_device_failed:
input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
i2c_set_clientdata(client, NULL);
err_i2c_failed:
kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
err_create_proc_entry:
return ret;
}
/*******************************************************
鍔熻兘锛? 椹卞姩璧勬簮閲婃斁
鍙傛暟锛? client锛氳澶囩粨鏋勪綋
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&ts->early_suspend);
#endif
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
remove_proc_entry("goodix-update", NULL);
#endif
if (ts && ts->use_irq)
{
#ifdef INT_PORT
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
#endif
free_irq(client->irq, ts);
}
else if(ts)
hrtimer_cancel(&ts->timer);
dev_notice(&client->dev,"The driver is removing...\n");
i2c_set_clientdata(client, NULL);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
//鍋滅敤璁惧
static int goodix_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->use_irq)
disable_irq(client->irq);
else
hrtimer_cancel(&ts->timer);
//ret = cancel_work_sync(&ts->work);
//if(ret && ts->use_irq)
//enable_irq(client->irq);
if (ts->power) { /* 蹇呴』鍦ㄥ彇娑坵ork鍚庡啀鎵ц锛岄伩鍏嶅洜GPIO瀵艰嚧鍧愭爣澶勭悊浠g爜姝诲惊鐜?*/
ret = ts->power(ts, 0);
if (ret < 0)
printk(KERN_ERR "goodix_ts_resume power off failed\n");
}
return 0;
}
//閲嶆柊鍞ら啋
static int goodix_ts_resume(struct i2c_client *client)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->power) {
ret = ts->power(ts, 1);
if (ret < 0)
printk(KERN_ERR "goodix_ts_resume power on failed\n");
}
if (ts->use_irq)
enable_irq(client->irq);
else
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_suspend(ts->client, PMSG_SUSPEND);
}
static void goodix_ts_late_resume(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_resume(ts->client);
}
#endif
//******************************Begin of firmware update surpport*******************************
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
/*
static int update_read_version(struct goodix_ts_data *ts, char **version)
{
int ret = -1, count = 0;
//unsigned char version_data[18];
char *version_data;
char *p;
*version = (char *)vmalloc(5);
version_data = *version;
if(!version_data)
return -ENOMEM;
p = version_data;
memset(version_data, 0, sizeof(version_data));
version_data[0]=0x07;
version_data[1]=0x17;
ret=i2c_read_bytes(ts->client,version_data, 4);
if (ret < 0)
return ret;
version_data[5]='\0';
if(*p == '\0')
return 0;
do
{
if((*p > 122) || (*p < 48 && *p != 32) || (*p >57 && *p < 65)
||(*p > 90 && *p < 97 && *p != '_')) //check illeqal character
count++;
}while(*++p != '\0' );
if(count > 2)
return 0;
else
return 1;
}
*/
/**
@brief CRC cal proc,include : Reflect,init_crc32_table,GenerateCRC32
@param global var oldcrc32
@return states
*/
static unsigned int Reflect(unsigned long int ref, char ch)
{
unsigned int value=0;
int i;
for(i = 1; i < (ch + 1); i++)
{
if(ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
/*---------------------------------------------------------------------------------------------------------*/
/* CRC Check Program INIT */
/*---------------------------------------------------------------------------------------------------------*/
/*
static void init_crc32_table(void)
{
unsigned int temp;
unsigned int t1,t2;
unsigned int flag;
int i,j;
for(i = 0; i <= 0xFF; i++)
{
temp=Reflect(i, 8);
crc32_table[i]= temp<< 24;
for (j = 0; j < 8; j++)
{
flag=crc32_table[i]&0x80000000;
t1=(crc32_table[i] << 1);
if(flag==0)
t2=0;
else
t2=ulPolynomial;
crc32_table[i] =t1^t2 ;
}
crc32_table[i] = Reflect(crc32_table[i], 32);
}
}
*/
/*---------------------------------------------------------------------------------------------------------*/
/* CRC main Program */
/*---------------------------------------------------------------------------------------------------------*/
/*
static void GenerateCRC32(unsigned char * buf, unsigned int len)
{
unsigned int i;
unsigned int t;
for (i = 0; i != len; ++i)
{
t = (oldcrc32 ^ buf[i]) & 0xFF;
oldcrc32 = ((oldcrc32 >> 8) & 0xFFFFFF) ^ crc32_table[t];
}
}
*/
static struct file * update_file_open(char * path, mm_segment_t * old_fs_p)
{
struct file * filp = NULL;
int errno = -1;
filp = filp_open(path, O_RDONLY, 0644);
if(!filp || IS_ERR(filp))
{
if(!filp)
errno = -ENOENT;
else
errno = PTR_ERR(filp);
printk(KERN_ERR "The update file for Guitar open error.\n");
return NULL;
}
*old_fs_p = get_fs();
set_fs(get_ds());
filp->f_op->llseek(filp,0,0);
return filp ;
}
static void update_file_close(struct file * filp, mm_segment_t old_fs)
{
set_fs(old_fs);
if(filp)
filp_close(filp, NULL);
}
static int update_get_flen(char * path)
{
struct file * file_ck = NULL;
mm_segment_t old_fs;
int length ;
file_ck = update_file_open(path, &old_fs);
if(file_ck == NULL)
return 0;
length = file_ck->f_op->llseek(file_ck, 0, SEEK_END);
//printk("File length: %d\n", length);
if(length < 0)
length = 0;
update_file_close(file_ck, old_fs);
return length;
}
/*
static int update_file_check(char * path)
{
unsigned char buffer[64] = { 0 } ;
struct file * file_ck = NULL;
mm_segment_t old_fs;
int count, ret, length ;
file_ck = update_file_open(path, &old_fs);
if(path != NULL)
printk("File Path:%s\n", path);
if(file_ck == NULL)
return -ERROR_NO_FILE;
length = file_ck->f_op->llseek(file_ck, 0, SEEK_END);
#ifdef GUITAR_MESSAGE
printk(KERN_INFO "gt801 update: File length: %d\n",length);
#endif
if(length <= 0 || (length%4) != 0)
{
update_file_close(file_ck, old_fs);
return -ERROR_FILE_TYPE;
}
//set file point to the begining of the file
file_ck->f_op->llseek(file_ck, 0, SEEK_SET);
oldcrc32 = 0xFFFFFFFF;
init_crc32_table();
while(length > 0)
{
ret = file_ck->f_op->read(file_ck, buffer, sizeof(buffer), &file_ck->f_pos);
if(ret > 0)
{
for(count = 0; count < ret; count++)
GenerateCRC32(&buffer[count],1);
}
else
{
update_file_close(file_ck, old_fs);
return -ERROR_FILE_READ;
}
length -= ret;
}
oldcrc32 = ~oldcrc32;
#ifdef GUITAR_MESSAGE
printk("CRC_Check: %u\n", oldcrc32);
#endif
update_file_close(file_ck, old_fs);
return 1;
}
unsigned char wait_slave_ready(struct goodix_ts_data *ts, unsigned short *timeout)
{
unsigned char i2c_state_buf[2] = {ADDR_STA, UNKNOWN_ERROR};
int ret;
while(*timeout < MAX_TIMEOUT)
{
ret = i2c_read_bytes(ts->client, i2c_state_buf, 2);
if(ret <= 0)
return ERROR_I2C_TRANSFER;
if(i2c_state_buf[1] & SL***E_READY)
{
return 1;
}
msleep(1);
*timeout += 5;
}
return 0;
}
*/
static int goodix_update_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
{
unsigned char cmd[120];
int ret = -1;
int retry = 0;
static unsigned char update_path[60];
struct goodix_ts_data *ts;
ts = i2c_get_clientdata(i2c_connect_client);
if(ts==NULL)
{
printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
return 0;
}
//printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
if(copy_from_user(&cmd, buff, len))
{
printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
return -EFAULT;
}
//printk(KERN_INFO"Write cmd is:%d,write len is:%ld\n",cmd[0], len);
switch(cmd[0])
{
case APK_UPDATE_TP:
printk(KERN_INFO"Write cmd is:%d,cmd arg is:%s,write len is:%ld\n",cmd[0], &cmd[1], len);
memset(update_path, 0, 60);
strncpy(update_path, cmd+1, 60);
ret = gt818_downloader( ts, goodix_gt818_firmware, update_path);
if(ret < 0)
{
printk(KERN_INFO"Warnning: GT818 update might be ERROR!\n");
return 0;
}
i2c_pre_cmd(ts);
msleep(2);
for(retry=0; retry<3; retry++)
{
ret=goodix_init_panel(ts);
printk(KERN_INFO"the config ret is :%d\n",ret);
msleep(2);
if(ret != 0) //Initiall failed
continue;
else
break;
}
//if(ts->use_irq)
// s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port as interrupt port
// else
gpio_direction_input(gt818_gpio_tp_irq);
i2c_end_cmd(ts);
if(ret != 0)
{
ts->bad_data=1;
return 1;
}
return 1;
case APK_READ_FUN: //functional command
if(cmd[1] == CMD_READ_VER)
{
printk(KERN_INFO"Read version!\n");
ts->read_mode = MODE_RD_VER;
}
else if(cmd[1] == CMD_READ_CFG)
{
printk(KERN_INFO"Read config info!\n");
ts->read_mode = MODE_RD_CFG;
}
return 1;
case APK_WRITE_CFG:
printk(KERN_INFO"Begin write config info!Config length:%d\n",cmd[1]);
i2c_pre_cmd(ts);
ret = i2c_write_bytes(ts->client, cmd+2, cmd[1]+2);
i2c_end_cmd(ts);
if(ret != 1)
{
printk("Write Config failed!return:%d\n",ret);
return -1;
}
return 1;
default:
return 0;
}
return 0;
}
static int goodix_update_read( char *page, char **start, off_t off, int count, int *eof, void *data )
{
int ret = -1;
struct goodix_ts_data *ts;
int len = 0;
unsigned char read_data[360] = {80, };
ts = i2c_get_clientdata(i2c_connect_client);
if(ts==NULL)
return 0;
printk("___READ__\n");
if(ts->read_mode == MODE_RD_VER) //read version data
{
i2c_pre_cmd(ts);
ret = goodix_read_version(ts);
i2c_end_cmd(ts);
if(ret <= 0)
{
printk(KERN_INFO"Read version data failed!\n");
return 0;
}
read_data[1] = (char)(ts->version&0xff);
read_data[0] = (char)((ts->version>>8)&0xff);
printk(KERN_INFO"Gt818 ROM version is:%x%x\n", read_data[0],read_data[1]);
memcpy(page, read_data, 2);
*eof = 1;
return 2;
}
else if(ts->read_mode == MODE_RD_CFG)
{
read_data[0] = 0x06;
read_data[1] = 0xa2; // cfg start address
printk("read config addr is:%x,%x\n", read_data[0],read_data[1]);
len = 106;
i2c_pre_cmd(ts);
ret = i2c_read_bytes(ts->client, read_data, len+2);
i2c_end_cmd(ts);
if(ret <= 0)
{
printk(KERN_INFO"Read config info failed!\n");
return 0;
}
memcpy(page, read_data+2, len);
return len;
}
return len;
}
#endif
//********************************************************************************************
static u8 is_equal( u8 *src , u8 *dst , int len )
{
int i;
for( i = 0 ; i < len ; i++ )
{
//printk(KERN_INFO"[%02X:%02X]\n", src[i], dst[i]);
}
for( i = 0 ; i < len ; i++ )
{
if ( src[i] != dst[i] )
{
return 0;
}
}
return 1;
}
static u8 gt818_nvram_store( struct goodix_ts_data *ts )
{
int ret;
int i;
u8 inbuf[3] = {REG_NVRCS_H,REG_NVRCS_L,0};
//u8 outbuf[3] = {};
ret = i2c_read_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
{
return 0;
}
if ( ( inbuf[2] & BIT_NVRAM_LOCK ) == BIT_NVRAM_LOCK )
{
return 0;
}
inbuf[2] = (1<<BIT_NVRAM_STROE); //store command
for ( i = 0 ; i < 300 ; i++ )
{
ret = i2c_write_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
break;
}
return ret;
}
static u8 gt818_nvram_recall( struct goodix_ts_data *ts )
{
int ret;
u8 inbuf[3] = {REG_NVRCS_H,REG_NVRCS_L,0};
ret = i2c_read_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
{
return 0;
}
if ( ( inbuf[2]&BIT_NVRAM_LOCK) == BIT_NVRAM_LOCK )
{
return 0;
}
inbuf[2] = ( 1 << BIT_NVRAM_RECALL ); //recall command
ret = i2c_write_bytes( ts->client , inbuf, 3);
return ret;
}
static int gt818_reset( struct goodix_ts_data *ts )
{
int ret = 1;
u8 retry;
unsigned char outbuf[3] = {0,0xff,0};
unsigned char inbuf[3] = {0,0xff,0};
//outbuf[1] = 1;
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(20);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(100);
for(retry=0;retry < 80; retry++)
{
ret =i2c_write_bytes(ts->client, inbuf, 0); //Test I2C connection.
if (ret > 0)
{
msleep(10);
ret =i2c_read_bytes(ts->client, inbuf, 3); //Test I2C connection.
if (ret > 0)
{
if(inbuf[2] == 0x55)
{
ret =i2c_write_bytes(ts->client, outbuf, 3);
msleep(10);
break;
}
}
}
}
printk(KERN_INFO"Detect address %0X\n", ts->client->addr);
//msleep(500);
return ret;
}
static int gt818_set_address_2( struct goodix_ts_data *ts )
{
unsigned char inbuf[3] = {0,0,0};
int i;
for ( i = 0 ; i < 12 ; i++ )
{
if ( i2c_read_bytes( ts->client, inbuf, 3) )
{
printk(KERN_INFO"Got response\n");
return 1;
}
printk(KERN_INFO"wait for retry\n");
msleep(50);
}
return 0;
}
static u8 gt818_update_firmware( u8 *nvram, u16 length, struct goodix_ts_data *ts)
{
u8 ret,err,retry_time,i;
u16 cur_code_addr;
u16 cur_frame_num, total_frame_num, cur_frame_len;
u32 gt80x_update_rate;
unsigned char i2c_data_buf[PACK_SIZE+2] = {0,}; //私戮莼潞麓鐖? unsigned char i2c_chk_data_buf[PACK_SIZE+2] = {0,}; //私戮莼潞麓鐖? err = 0;
if( length > NVRAM_LEN - NVRAM_BOOT_SECTOR_LEN )
{
printk(KERN_INFO"length too big %d %d\n", length, NVRAM_LEN - NVRAM_BOOT_SECTOR_LEN );
return 0;
}
total_frame_num = ( length + PACK_SIZE - 1) / PACK_SIZE;
//gt80x_update_sta = _UPDATING;
gt80x_update_rate = 0;
for( cur_frame_num = 0 ; cur_frame_num < total_frame_num ; cur_frame_num++ )
{
retry_time = 5;
cur_code_addr = NVRAM_UPDATE_START_ADDR + cur_frame_num * PACK_SIZE;
i2c_data_buf[0] = (cur_code_addr>>8)&0xff;
i2c_data_buf[1] = cur_code_addr&0xff;
i2c_chk_data_buf[0] = i2c_data_buf[0];
i2c_chk_data_buf[1] = i2c_data_buf[1];
if( cur_frame_num == total_frame_num - 1 )
{
cur_frame_len = length - cur_frame_num * PACK_SIZE;
}
else
{
cur_frame_len = PACK_SIZE;
}
//strncpy(&i2c_data_buf[2], &nvram[cur_frame_num*PACK_SIZE], cur_frame_len);
for(i=0;i<cur_frame_len;i++)
{
i2c_data_buf[2+i] = nvram[cur_frame_num*PACK_SIZE+i];
}
do
{
err = 0;
//ret = gt818_i2c_write( guitar_i2c_address, cur_code_addr, &nvram[cur_frame_num*I2C_FRAME_MAX_LENGTH], cur_frame_len );
ret = i2c_write_bytes(ts->client, i2c_data_buf, (cur_frame_len+2));
if ( ret <= 0 )
{
printk(KERN_INFO"write fail\n");
err = 1;
}
ret = i2c_read_bytes(ts->client, i2c_chk_data_buf, (cur_frame_len+2));
// ret = gt818_i2c_read( guitar_i2c_address, cur_code_addr, inbuf, cur_frame_len);
if ( ret <= 0 )
{
printk(KERN_INFO"read fail\n");
err = 1;
}
if( is_equal( &i2c_data_buf[2], &i2c_chk_data_buf[2], cur_frame_len ) == 0 )
{
printk(KERN_INFO"not equal\n");
err = 1;
}
} while ( err == 1 && (--retry_time) > 0 );
if( err == 1 )
{
break;
}
gt80x_update_rate = ( cur_frame_num + 1 )*128/total_frame_num;
}
if( err == 1 )
{
printk(KERN_INFO"write nvram fail\n");
return 0;
}
ret = gt818_nvram_store(ts);
msleep( 20 );
if( ret == 0 )
{
printk(KERN_INFO"nvram store fail\n");
return 0;
}
ret = gt818_nvram_recall(ts);
msleep( 20 );
if( ret == 0 )
{
printk(KERN_INFO"nvram recall fail\n");
return 0;
}
for ( cur_frame_num = 0 ; cur_frame_num < total_frame_num ; cur_frame_num++ ) // read out all the code
{
cur_code_addr = NVRAM_UPDATE_START_ADDR + cur_frame_num*PACK_SIZE;
retry_time=5;
i2c_chk_data_buf[0] = (cur_code_addr>>8)&0xff;
i2c_chk_data_buf[1] = cur_code_addr&0xff;
if ( cur_frame_num == total_frame_num-1 )
{
cur_frame_len = length - cur_frame_num*PACK_SIZE;
}
else
{
cur_frame_len = PACK_SIZE;
}
do
{
err = 0;
//ret = gt818_i2c_read( guitar_i2c_address, cur_code_addr, inbuf, cur_frame_len);
ret = i2c_read_bytes(ts->client, i2c_chk_data_buf, (cur_frame_len+2));
if ( ret == 0 )
{
err = 1;
}
if( is_equal( &nvram[cur_frame_num*PACK_SIZE], &i2c_chk_data_buf[2], cur_frame_len ) == 0 )
{
err = 1;
}
} while ( err == 1 && (--retry_time) > 0 );
if( err == 1 )
{
break;
}
gt80x_update_rate = 127 + ( cur_frame_num + 1 )*128/total_frame_num;
}
gt80x_update_rate = 255;
//gt80x_update_sta = _UPDATECHKCODE;
if( err == 1 )
{
printk(KERN_INFO"nvram validate fail\n");
return 0;
}
//往0X00FF写0XCC表示烧录结束
i2c_chk_data_buf[0] = 0xff;
i2c_chk_data_buf[1] = 0x00;
i2c_chk_data_buf[2] = 0x0;
ret = i2c_write_bytes(ts->client, i2c_chk_data_buf, 3);
if( ret <= 0 )
{
printk(KERN_INFO"nvram validate fail\n");
return 0;
}
return 1;
}
static u8 gt818_update_proc( u8 *nvram, u16 length, struct goodix_ts_data *ts )
{
u8 ret;
u8 error = 0;
//struct tpd_info_t tpd_info;
GT818_SET_INT_PIN( 0 );
msleep( 20 );
ret = gt818_reset(ts);
if ( ret < 0 )
{
error = 1;
printk(KERN_INFO"reset fail\n");
goto end;
}
ret = gt818_set_address_2( ts );
if ( ret == 0 )
{
error = 1;
printk(KERN_INFO"set address fail\n");
goto end;
}
ret = gt818_update_firmware( nvram, length, ts);
if ( ret == 0 )
{
error=1;
printk(KERN_INFO"firmware update fail\n");
goto end;
}
end:
//GT818_SET_INT_PIN( 1 );
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
msleep( 500 );
ret = gt818_reset(ts);
if ( ret < 0 )
{
error=1;
printk(KERN_INFO"final reset fail\n");
goto end;
}
if ( error == 1 )
{
return 0;
}
i2c_pre_cmd(ts);
while(goodix_read_version(ts)<0);
i2c_end_cmd(ts);
return 1;
}
static int gt818_downloader( struct goodix_ts_data *ts, unsigned char * data, unsigned char * path)
{
struct tpd_firmware_info_t *fw_info = (struct tpd_firmware_info_t *)data;
int i;
unsigned short checksum = 0;
unsigned char *data_ptr = &(fw_info->data);
int retry = 0,ret;
int err = 0;
struct file * file_data = NULL;
mm_segment_t old_fs;
//unsigned int rd_len;
unsigned int file_len = 0;
//unsigned char i2c_data_buf[PACK_SIZE] = {0,};
const int MAGIC_NUMBER_1 = 0x4D454449;
const int MAGIC_NUMBER_2 = 0x4154454B;
if(path[0] == 0)
{
printk(KERN_INFO"%s\n", __func__ );
printk(KERN_INFO"magic number 0x%08X 0x%08X\n", fw_info->magic_number_1, fw_info->magic_number_2 );
printk(KERN_INFO"magic number 0x%08X 0x%08X\n", MAGIC_NUMBER_1, MAGIC_NUMBER_2 );
printk(KERN_INFO"current version 0x%04X, target verion 0x%04X\n", ts->version, fw_info->version );
printk(KERN_INFO"size %d\n", fw_info->length );
printk(KERN_INFO"checksum %d\n", fw_info->checksum );
if ( fw_info->magic_number_1 != MAGIC_NUMBER_1 && fw_info->magic_number_2 != MAGIC_NUMBER_2 )
{
printk(KERN_INFO"Magic number not match\n");
err = 0;
goto exit_downloader;
}
if(((ts->version&0xff)> 0x99)||((ts->version&0xff) < 0x4a))
{
goto update_start;
}
if ( ts->version >= fw_info->version )
{
printk(KERN_INFO"No need to upgrade\n");
err = 0;
goto exit_downloader;
}
if ( get_chip_version( ts->version ) != get_chip_version( fw_info->version ) )
{
printk(KERN_INFO"Chip version incorrect");
err = 0;
goto exit_downloader;
}
update_start:
for ( i = 0 ; i < fw_info->length ; i++ )
checksum += data_ptr[i];
checksum = checksum%0xFFFF;
if ( checksum != fw_info->checksum )
{
printk(KERN_INFO"Checksum not match 0x%04X\n", checksum);
err = 0;
goto exit_downloader;
}
}
else
{
printk(KERN_INFO"Write cmd arg is:\n");
file_data = update_file_open(path, &old_fs);
printk(KERN_INFO"Write cmd arg is\n");
if(file_data == NULL) //file_data has been opened at the last time
{
err = -1;
goto exit_downloader;
}
file_len = (update_get_flen(path))-2;
printk(KERN_INFO"current length:%d\n", file_len);
ret = file_data->f_op->read(file_data, &data_ptr[0], file_len, &file_data->f_pos);
if(ret <= 0)
{
err = -1;
goto exit_downloader;
}
update_file_close(file_data, old_fs);
}
printk(KERN_INFO"STEP_0:\n");
//adapter = client->adapter;
gpio_free(gt818_gpio_tp_irq);
ret = gpio_request(gt818_gpio_tp_irq, "TS_INT"); //Request IO
if (ret < 0)
{
printk(KERN_INFO"Failed to request GPIO:%d, ERRNO:%d\n",(int)gt818_gpio_tp_irq,ret);
err = -1;
goto exit_downloader;
}
printk(KERN_INFO"STEP_1:\n");
err = -1;
while ( retry < 3 )
{
ret = gt818_update_proc( data_ptr, fw_info->length, ts);
if(ret == 1)
{
err = 1;
break;
}
retry++;
}
exit_downloader:
//mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
// mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ONE);
// gpio_direction_output(gt818_gpio_tp_irq,1);
// msleep(1);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
return err;
}
//******************************End of firmware update surpport*******************************
//鍙敤浜庤椹卞姩鐨?璁惧鍚嶁€旇澶嘔D 鍒楄〃
//only one client
static const struct i2c_device_id goodix_ts_id[] = {
{ GOODIX_I2C_NAME, 0 },
{ }
};
//璁惧椹卞姩缁撴瀯浣?static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = goodix_ts_suspend,
.resume = goodix_ts_resume,
#endif
.id_table = goodix_ts_id,
.driver = {
.name = GOODIX_I2C_NAME,
.owner = THIS_MODULE,
},
};
/*******************************************************
鍔熻兘锛? 椹卞姩鍔犺浇鍑芥暟
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int __devinit goodix_ts_init(void)
{
// int ret;
printk("wax->%s\n",__FUNCTION__);
goodix_wq = create_workqueue("goodix_wq"); //create a work queue and worker thread
if (!goodix_wq) {
printk(KERN_ALERT "creat workqueue faiked\n");
return -ENOMEM;
}
printk("%s\n", __func__);
gt818_gpio_tp_irq_int_num=gt818_config_pins();
gt818_ts_setup.i2c_bus = 2;
gt818_ts_setup.i2c_address = GT818_TS_ADDR;
strcpy (gt818_ts_setup.type,GOODIX_I2C_NAME);
gt818_ts_setup.irq = gt818_gpio_tp_irq_int_num;
return gt818_sprd_add_i2c_device(>818_ts_setup, &goodix_ts_driver);
//ret=i2c_add_driver(&goodix_ts_driver);
//return ret;
}
/*******************************************************
鍔熻兘锛? 椹卞姩鍗歌浇鍑芥暟
鍙傛暟锛? client锛氳澶囩粨鏋勪綋
********************************************************/
static void __exit goodix_ts_exit(void)
{
printk(KERN_ALERT "Touchscreen driver of guitar exited.\n");
sprd_free_gpio_irq(gt818_gpio_tp_irq_int_num);
//i2c_del_driver(&goodix_ts_driver);
gt818_sprd_del_i2c_device(i2c_connect_client,&goodix_ts_driver);
if (goodix_wq)
destroy_workqueue(goodix_wq); //release our work queue
}
late_initcall(goodix_ts_init); //鏈€鍚庡垵濮嬪寲椹卞姩felix
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Driver");
MODULE_LICENSE("GPL");
.../build.sh
.../driver
.../driver/gt818.h
.../driver/gt818_update.h
.../driver/gt818.mod.c //编译时自动生成
.../driver/gt818.c //主要驱动文件
.../driver/Makefile
.../firmware
.../firmware/update_0080.bin //固件
.../init.3rdparty.rc
备注:头文件(gt818.h) 请查看如下链接,这两份都是完整的代码。gt818_update.h 对于使用来说没有什么用处,可以不用。
/article/1921593.html
头文件(gt818_update.h)请查看如下链接。 内容很简单,就是一个存储参数的数组。
http://blog.csdn.net/duanlove/article/details/11127833
--------------------------------------------- gt818.c -----------------------------------------------------------------------------
/* drivers/input/touchscreen/goodix_touch.c
*
* Copyright (C) 2011 Goodix, Inc.
*
* Author: Felix
* Date: 2011.04.28
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/earlysuspend.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <mach/gpio.h>
//#include <plat/gpio-cfg.h>
//#include <plat/gpio-bank-l.h>
//#include <plat/gpio-bank-f.h>
#include <linux/irq.h>
#include <linux/syscalls.h>
#include <linux/reboot.h>
#include <linux/proc_fs.h>
#include "gt818.h"//<linux/gt818.h>
#include "gt818_update.h"//<linux/gt818_50.h>
//#include <linux/goodix_queue.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/completion.h>
#include <asm/uaccess.h>
#include <mach/ldo.h>
#include <mach/regs_ana.h>
#if !defined(GT801_PLUS) && !defined(GT801_NUVOTON)
#error The code does not match this touchscreen.
#endif
static struct workqueue_struct *goodix_wq;
static const char *s3c_ts_name = "pixcir_ts";
//static struct point_queue finger_list;
struct i2c_client * i2c_connect_client = NULL;
//EXPORT_SYMBOL(i2c_connect_client);
static struct proc_dir_entry *goodix_proc_entry;
static short goodix_read_version(struct goodix_ts_data *ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
static int gt818_downloader( struct goodix_ts_data *ts, unsigned char * data,unsigned char * path );
#endif
//used by firmware update CRC
unsigned int oldcrc32 = 0xFFFFFFFF;
unsigned int crc32_table[256];
unsigned int ulPolynomial = 0x04c11db7;
//static int gt818_gpio_tp_irq=0;
//static int shout_down_num=0;
//static int int_cfg_num=0;
//static int ts_int=0;
static int gt818_gpio_tp_irq_int_num=0;
static int gt818_gpio_tp_rst = 59;
static int gt818_gpio_tp_irq = 60;
static int gt818_wrong_num =0;
#define TS_DEBUG_MSG 1
//#define I2C_BOARD_INFO_METHOD 0
//#define TS_DATA_THRESHOLD_CHECK 1
//#define TS_WIDTH_MAX 320
//#define TS_HEIGHT_MAX 480
//static int debug_level=0;
#if TS_DEBUG_MSG
#define TS_DBG(format, ...) \
printk(KERN_INFO "gt818 " format "\n", ## __VA_ARGS__)
#else
#define TS_DBG(format, ...)
#endif
static struct sprd_i2c_setup_data {
unsigned i2c_bus; //the same number as i2c->adap.nr in adapter probe function
unsigned short i2c_address;
int irq;
char type[I2C_NAME_SIZE];
};
static struct sprd_i2c_setup_data gt818_ts_setup={1, GT818_TS_ADDR, 0, GOODIX_I2C_NAME};
static int gt818_sprd_add_i2c_device(struct sprd_i2c_setup_data *i2c_set_data, struct i2c_driver *driver)
{
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client;
int ret,err;
TS_DBG("%s : i2c_bus=%d; slave_address=0x%x; i2c_name=%s",__func__,i2c_set_data->i2c_bus, \
i2c_set_data->i2c_address, i2c_set_data->type);
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = i2c_set_data->i2c_address;
strlcpy(info.type, i2c_set_data->type, I2C_NAME_SIZE);
if(i2c_set_data->irq > 0)
info.irq = i2c_set_data->irq;
adapter = i2c_get_adapter( i2c_set_data->i2c_bus);
if (!adapter) {
printk("%s: can't get i2c adapter %d\n",
__func__, i2c_set_data->i2c_bus);
err = -ENODEV;
goto err_driver;
}
client = i2c_new_device(adapter, &info);
if (!client) {
printk("%s: can't add i2c device at 0x%x\n",
__func__, (unsigned int)info.addr);
err = -ENODEV;
goto err_driver;
}
i2c_put_adapter(adapter);
ret = i2c_add_driver(driver);
if (ret != 0) {
printk("%s: can't add i2c driver\n", __func__);
err = -ENODEV;
goto err_driver;
}
return 0;
err_driver:
return err;
}
static void gt818_sprd_del_i2c_device(struct i2c_client *client, struct i2c_driver *driver)
{
TS_DBG("%s : slave_address=0x%x; i2c_name=%s",__func__, client->addr, client->name);
i2c_unregister_device(client);
i2c_del_driver(driver);
}
//static struct sprd_i2c_setup_data ft5x0x_ts_setup={0, FT5206_TS_ADDR_R, 0, FT5206_TS_NAME};
/*******************************************************************************
* Function : ft5x0x_ts_config_pins
* Description : config gpio pins and set relative TS pins
* Parameters : void
* Return : int irq_num;
*******************************************************************************/
static int gt818_config_pins(void)
{
int gt818irq;
gpio_direction_output(gt818_gpio_tp_rst, 1);
gpio_direction_input(gt818_gpio_tp_irq);
gpio_set_value(gt818_gpio_tp_rst, 1);
gt818irq=sprd_alloc_gpio_irq(gt818_gpio_tp_irq);
msleep(10); //wait for stable
return gt818irq;
}
/*******************************************************
鍔熻兘锛?
璇诲彇浠庢満鏁版嵁
姣忎釜璇绘搷浣滅敤涓ゆ潯i2c_msg缁勬垚锛岀1鏉℃秷鎭敤浜庡彂閫佷粠鏈哄湴鍧€锛? 绗?鏉$敤浜庡彂閫佽鍙栧湴鍧€鍜屽彇鍥炴暟鎹紱姣忔潯娑堟伅鍓嶅彂閫佽捣濮嬩俊鍙?鍙傛暟锛? client: i2c璁惧锛屽寘鍚澶囧湴鍧€
buf[0]锛?棣栧瓧鑺備负璇诲彇鍦板潃
buf[1]~buf[len]锛氭暟鎹紦鍐插尯
len锛?璇诲彇鏁版嵁闀垮害
return锛? 鎵ц娑堟伅鏁?*********************************************************/
/*Function as i2c_master_send */
static int i2c_read_bytes(struct i2c_client *client, uint8_t *buf, int len)
{
struct i2c_msg msgs[2];
int ret=-1;
//鍙戦€佸啓鍦板潃
msgs[0].flags=!I2C_M_RD;//鍐欐秷鎭? msgs[0].addr=client->addr;
msgs[0].len=2;
msgs[0].buf=&buf[0];
//鎺ユ敹鏁版嵁
msgs[1].flags=I2C_M_RD;//璇绘秷鎭? msgs[1].addr=client->addr;
msgs[1].len=len-2;
msgs[1].buf=&buf[2];
ret=i2c_transfer(client->adapter,msgs, 2);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍚戜粠鏈哄啓鏁版嵁
鍙傛暟锛? client: i2c璁惧锛屽寘鍚澶囧湴鍧€
buf[0]锛?棣栧瓧鑺備负鍐欏湴鍧€
buf[1]~buf[len]锛氭暟鎹紦鍐插尯
len锛?鏁版嵁闀垮害
return锛? 鎵ц娑堟伅鏁?*******************************************************/
/*Function as i2c_master_send */
static int i2c_write_bytes(struct i2c_client *client,uint8_t *data,int len)
{
struct i2c_msg msg;
int ret=-1;
//鍙戦€佽澶囧湴鍧€
msg.flags=!I2C_M_RD;//鍐欐秷鎭? msg.addr=client->addr;
msg.len=len;
msg.buf=data;
ret=i2c_transfer(client->adapter,&msg, 1);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍙戦€佸墠缂€鍛戒护
ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛?
鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int i2c_pre_cmd(struct goodix_ts_data *ts)
{
int ret;
uint8_t pre_cmd_data[2]={0};
pre_cmd_data[0]=0x0f;
pre_cmd_data[1]=0xff;
ret=i2c_write_bytes(ts->client,pre_cmd_data,2);
//msleep(2);
return ret;
}
/*******************************************************
鍔熻兘锛? 鍙戦€佸悗缂€鍛戒护
ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛?
鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int i2c_end_cmd(struct goodix_ts_data *ts)
{
int ret;
uint8_t end_cmd_data[2]={0};
end_cmd_data[0]=0x80;
end_cmd_data[1]=0x00;
ret=i2c_write_bytes(ts->client,end_cmd_data,2);
//msleep(2);
return ret;
}
/*
*/
static short get_chip_version( unsigned int sw_ver )
{
if ( (sw_ver&0xff) < TPD_CHIP_VERSION_C_FIRMWARE_BASE )
return TPD_GT818_VERSION_B;
else if ( (sw_ver&0xff) < TPD_CHIP_VERSION_D_FIRMWARE_BASE )
return TPD_GT818_VERSION_C;
else
return TPD_GT818_VERSION_D;
}
/*******************************************************
鍔熻兘锛? Guitar鍒濆鍖栧嚱鏁帮紝鐢ㄤ簬鍙戦€侀厤缃俊鎭紝鑾峰彇鐗堟湰淇℃伅
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static int goodix_init_panel(struct goodix_ts_data *ts)
{
short ret=-1;
// int ic_size = 0;
#if 1
uint8_t config_info_c[] = { //Touch key devlop board
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x01,0x13,0x80,0x88,0x90,0x14,
0x15,0x40,0x0F,0x0F,0x0A,0x50,0x3C,0x0C,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
};
uint8_t config_info_d[] = { //Touch key devlop board
#if 0
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x0B,0x13,0x90,0x90,0x90,0x27,
0x27,0x27,0x0F,0x0F,0x0A,0x50,0x3C,0x4B,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x05,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
/*0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x00,0x00,0x01,0x13,0x80,0x88,0x90,0x14,
0x15,0x40,0x0F,0x0F,0x0A,0x50,0x3C,0x0C,
0x00,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x46,0x5A,0x00,0x00,0x00,0x00,0x03,
0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00,
0x20,0x10,0x00,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38,
0x00,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
*/
#endif
#if 1 //defined(CONFIG_S9_IPhone) //s9 hua fei jeed
/*0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x02,0x22,0x12,0x22,0x22,0x22,
0x32,0x22,0x42,0x22,0x52,0x22,0x62,0x22,
0xE2,0x22,0xD2,0x22,0xC2,0x22,0xB2,0x22,
0xA2,0x22,0x92,0x22,0x82,0x22,0x72,0x22,
0xF2,0x22,0x37,0x03,0xA8,0xA8,0xA8,0x1A,
0x1A,0x1A,0x0F,0x0E,0x0A,0x48,0x38,0x09,
//0x03,0x00,0x05,0x40,0x01,0xE0,0x01,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x57,0x60,0x5A,0x00,0x00,0x23,
0x14,0x05,0x05,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0xCE,0x03,0x00,0x40,0x37,0x10,
0x31,0x00,0x40,0x50,0x60,0x70,0x0D,0x40,
0x30,0x25,0x20,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
/*0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x60,0x00,0x50,0x00,0x40,0x00,
0x30,0x00,0x20,0x00,0x10,0x00,0x00,0x00,
0xF0,0x00,0xE0,0x00,0xD0,0x00,0xC0,0x00,
0xB0,0x00,0xA0,0x00,0x90,0x00,0x80,0x00,
0x70,0x00,0x1B,0x03,0x70,0x70,0x70,0x26,
0x26,0x26,0x10,0x0F,0x0A,0x50,0x30,0x45,
//0x03,0x16,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x55,0x4F,0x58,0x52,0x00,0x00,0x03,
0x14,0x05,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x40,0x37,0x50,
0x26,0x00,0x10,0x20,0x00,0x00,0x0D,0x40,
0x30,0x3C,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
/*
0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0xF0,0x00,0xE0,0x00,0xD0,0x00,
0xC0,0x00,0xB0,0x00,0xA0,0x00,0x90,0x00,
0x80,0x00,0x1B,0x03,0x70,0x70,0x70,0x27,
0x27,0x27,0x10,0x0F,0x0A,0x50,0x30,0x0D,
//0x03,0x16,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x55,0x4F,0x58,0x52,0x00,0x00,0x03,
0x14,0x05,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x40,0x37,0x30,
0x26,0x00,0x70,0x80,0x90,0xA0,0x0D,0x40,
0x30,0x3C,0x14,0x00,0x00,0x00,0x00,0x00,
0x00,0x01*/
0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x00,0x00,0x10,0x00,0x20,0x00,
0x30,0x00,0x40,0x00,0x50,0x00,0x60,0x00,
0x70,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x3B,0x13,0x10,0x10,0x10,0x1E,
0x1E,0x1E,0x10,0x0F,0x0A,0x5A,0x4A,0x4F,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x50,0x49,0x54,0x4C,0x00,0x00,0x1B,
0x14,0x05,0x0A,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x31,0x03,0x00,0x40,0x3B,0x10,
0x21,0x00,0x70,0x80,0x90,0xA0,0x0B,0x50,
0x40,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#elif 0 //defined(CONFIG_S1_IPhone) // s1 lce
0x06,0xA2,
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0x07,0x03,0x10,0x10,0x10,0x24,
0x24,0x24,0x10,0x0F,0x0A,0x40,0x30,0x0D,
//0x03,0x00,0x05,0x00,0x14,0x00,0x1E,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5A,0x5D,0x5E,0x61,0x00,0x00,0x03,
0x14,0x00,0x06,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0xEF,0x03,0x00,0x00,0x00,0x00,
0x00,0x00,0x22,0x45,0x6C,0x92,0x0D,0x40,
0x30,0x25,0x20,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#elif 0 //s9 hua fei soeya
/*0x06,0xA2,
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,
0x10,0x12,0x81,0x11,0x91,0x11,0xA1,0x11,
0xB1,0x11,0xC1,0x11,0xD1,0x11,0xE1,0x11,
0x71,0x11,0x61,0x11,0x51,0x11,0x41,0x11,
0x31,0x11,0x21,0x11,0x11,0x11,0x01,0x11,
0xF1,0x11,0x07,0x03,0x10,0x10,0x10,0x25,
0x25,0x25,0x0F,0x0E,0x0A,0x40,0x30,0x09,
//0x03,0x00,0x05,0x40,0x01,0xE0,0x01,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x4F,0x60,0x53,0x00,0x00,0x02,
0x14,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x74,0x03,0x00,0x30,0x37,0x10,
0x28,0x00,0x40,0x72,0x61,0x50,0x0F,0x35,
0x25,0x25,0x1A,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
*/
#else
0x06,0xA2, // lce jeed
0x12,0x10,0x0E,0x0C,0x0A,0x08,0x06,0x04,
0x02,0x00,0x70,0x00,0x60,0x00,0x50,0x00,
0x40,0x00,0x30,0x00,0x20,0x00,0x10,0x00,
0x00,0x00,0x80,0x00,0x90,0x00,0xA0,0x00,
0xB0,0x00,0xC0,0x00,0xD0,0x00,0xE0,0x00,
0xF0,0x00,0x17,0x13,0xE8,0xE8,0xE8,0x1C,
0x1C,0x1C,0x10,0x0F,0x0A,0x50,0x40,0x09,
//0x03,0x00,0x05,0xE0,0x01,0x20,0x03,0x00,
0x03,0x00,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00,
0x00,0x5C,0x5C,0x60,0x60,0x00,0x00,0x23,
0x14,0x00,0x0A,0x00,0x00,0x00,0x00,0x00,
0x14,0x10,0x06,0x04,0x00,0x40,0x17,0x10,
0x1E,0x00,0x30,0x40,0x50,0x60,0x0A,0x50,
0x40,0x3C,0x28,0x00,0x00,0x00,0x00,0x00,
0x00,0x01
#endif
};
#endif
ret = goodix_read_version(ts);
if (ret < 0)
return ret;
dev_info(&ts->client->dev," Guitar Version: %d\n",ts->version);
if((ts->version&0xff) < TPD_CHIP_VERSION_D_FIRMWARE_BASE)
{
dev_info(&ts->client->dev," Guitar Version: C\n");
config_info_c[57] = (config_info_c[57]&0xf7)|(INT_TRIGGER<<3);
ret=i2c_write_bytes(ts->client,config_info_c, (sizeof(config_info_c)/sizeof(config_info_c[0])));
}
else
{
dev_info(&ts->client->dev," Guitar Version: D\n");
config_info_d[57] = (config_info_d[57]&0xf7)|(INT_TRIGGER<<3);
ret=i2c_write_bytes(ts->client,config_info_d, (sizeof(config_info_d)/sizeof(config_info_d[0])));
}
if (ret < 0)
return ret;
msleep(10);
return 0;
}
/*******************************************************
鍔熻兘锛? 鑾峰彇鐗堟湰淇℃伅
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
*******************************************************/
static short goodix_read_version(struct goodix_ts_data *ts)
{
short ret;
uint8_t version_data[5]={0}; //store touchscreen version infomation
memset(version_data, 0, 5);
version_data[0]=0x07;
version_data[1]=0x17;
msleep(5);
//ret=i2c_read_bytes(ts->client, version_data, 4);
//msleep(2);
ret=i2c_read_bytes(ts->client, version_data, 4);
if (ret < 0)
return ret;
dev_info(&ts->client->dev," Guitar Version: %d.%d\n",version_data[3],version_data[2]);
ts->version = (version_data[3]<<8)+version_data[2];
return ret;
}
/*******************************************************
鍔熻兘锛? 瑙︽懜灞忓伐浣滃嚱鏁? 鐢变腑鏂Е鍙戯紝鎺ュ彈1缁勫潗鏍囨暟鎹紝鏍¢獙鍚庡啀鍒嗘瀽杈撳嚭
鍙傛暟锛? ts: client绉佹湁鏁版嵁缁撴瀯浣?return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{
uint8_t touch_data[3] = {READ_TOUCH_ADDR_H,READ_TOUCH_ADDR_L,0};
uint8_t key_data[3] ={READ_KEY_ADDR_H,READ_KEY_ADDR_L,0};
uint8_t point_data[8*MAX_FINGER_NUM+2]={ 0 };
static uint8_t finger_last[MAX_FINGER_NUM+1]={0}; //涓婃瑙︽懜鎸夐敭鐨勬墜鎸囩储寮? uint8_t finger_current[MAX_FINGER_NUM+1] = {0}; //褰撳墠瑙︽懜鎸夐敭鐨勬墜鎸囩储寮? uint8_t coor_data[6*MAX_FINGER_NUM] = {0}; //瀵瑰簲鎵嬫寚鐨勬暟鎹? static uint8_t last_key = 0;
uint8_t finger = 0;
uint8_t key = 0;
unsigned int count = 0;
unsigned int position = 0;
int ret=-1;
int tmp = 0;
int temp = 0;
uint16_t *coor_point;
//printk("goodix \n");
struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
i2c_pre_cmd(ts);
#ifndef INT_PORT
COORDINATE_POLL:
#endif
if( tmp > 9) {
dev_info(&(ts->client->dev), "Because of transfer error,touchscreen stop working.\n");
goto XFER_ERROR ;
}
ret=i2c_read_bytes(ts->client, touch_data,sizeof(touch_data)/sizeof(touch_data[0])); //璇?x712锛岃Е鎽? if(ret <= 0) {
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
#ifdef H***E_TOUCH_KEY
ret=i2c_read_bytes(ts->client, key_data,sizeof(key_data)/sizeof(key_data[0])); //璇?x721锛屾寜閿?
if(ret <= 0) {
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
key = key_data[2]&0x0f;
#endif
if(ts->bad_data)
//TODO:Is sending config once again (to reset the chip) useful?
msleep(20);
#if 1
if(touch_data[2] == 0x0f)
{
printk("goodix 01=%x\n",touch_data[2]);
goodix_init_panel(ts);
goto DATA_NO_READY;
}
if((touch_data[2]&0x30)!=0x20)
{
printk("goodix 02=%x\n",touch_data[2]&0x30);
gt818_wrong_num++;
if(gt818_wrong_num>5)
{
gt818_wrong_num=0;
goodix_init_panel(ts);
}
goto DATA_NO_READY;
}
gt818_wrong_num=0;
#else
printk("goodix %x\n",touch_data[2]);
if((touch_data[2]&0x30)!=0x20)
{
printk("goodix 01=%x\n",touch_data[2]&0x30);
gt818_wrong_num++;
if(gt818_wrong_num>5)
{
gt818_wrong_num=0;
//goodix_init_panel(ts);
}
goto DATA_NO_READY;
}
gt818_wrong_num=0;
if((touch_data[2]&0x0f) == 0x0f)
{
printk("goodix 02=%x\n",touch_data[2]&0x0f);
goodix_init_panel(ts);
goto DATA_NO_READY;
}
#endif
ts->bad_data = 0;
finger = touch_data[2]&0x0f;
if(finger != 0)
{
point_data[0] = READ_COOR_ADDR_H; //read coor high address
point_data[1] = READ_COOR_ADDR_L; //read coor low address
ret=i2c_read_bytes(ts->client, point_data, finger*8+2);
if(ret <= 0)
{
dev_err(&(ts->client->dev),"I2C transfer error. Number:%d\n ", ret);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
for(position=2; position<((finger-1)*8+2+1); position += 8)
{
temp = point_data[position];
if(temp<(MAX_FINGER_NUM+1))
{
finger_current[temp] = 1;
for(count=0; count<6; count++)
{
coor_data[(temp-1)*6+count] = point_data[position+1+count]; //璁板綍褰撳墠鎵嬫寚绱㈠紩锛屽苟瑁呰浇鍧愭爣鏁版嵁
}
}
else
{
dev_err(&(ts->client->dev),"Track Id error:%d\n ",0);
ts->bad_data = 1;
tmp ++;
ts->retry++;
#ifndef INT_PORT
goto COORDINATE_POLL;
#else
goto XFER_ERROR;
#endif
}
}
//coor_point = (uint16_t *)coor_data;
}
else
{
for(position=1;position < MAX_FINGER_NUM+1; position++)
{
finger_current[position] = 0;
}
}
coor_point = (uint16_t *)coor_data;
for(position=1;position < MAX_FINGER_NUM+1; position++)
{
if((finger_current[position] == 0)&&(finger_last[position] != 0))
{
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 0);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, 0);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
// input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
input_mt_sync(ts->input_dev);
//printk("report error\n");
}
else if(finger_current[position])
{
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, (*(coor_point+3*(position-1)))); //can change x-y!!!
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, (*(coor_point+3*(position-1)+1)));
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,1);
//input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, finger_list.pointer[0].pressure);
input_mt_sync(ts->input_dev);
// input_report_abs(ts->input_dev, ABS_X, finger_list.pointer[0].x);
// input_report_abs(ts->input_dev, ABS_Y, finger_list.pointer[0].y)
// input_report_abs(ts->input_dev, ABS_PRESSURE, finger_list.pointer[0].pressure);
// input_sync(ts->input_dev);
// printk("%d*",(*(coor_point+3*(position-1)))*SCREEN_MAX_HEIGHT/(TOUCH_MAX_HEIGHT));
// printk("%d*",(*(coor_point+3*(position-1)+1))*SCREEN_MAX_WIDTH/(TOUCH_MAX_WIDTH));
// printk("\n");
//printk("x=%d ",(*(coor_point+3*(position-1))));
//printk("y=%d ",(*(coor_point+3*(position-1)+1)));
printk("\n");
}
}
input_sync(ts->input_dev);
for(position=1;position<MAX_FINGER_NUM+1; position++)
{
finger_last[position] = finger_current[position];
}
#ifdef H***E_TOUCH_KEY
if((last_key == 0)&&(key == 0))
;
else
{
for(count = 0; count < 4; count++)
{
input_report_key(ts->input_dev, touch_key_array[count], !!(key&(0x01<<count)));
}
//printk("goodix key=%d \n",key);
}
last_key = key;
#endif
DATA_NO_READY:
XFER_ERROR:
i2c_end_cmd(ts);
if(ts->use_irq)
enable_irq(ts->client->irq);
}
/*******************************************************
鍔熻兘锛? 璁℃椂鍣ㄥ搷搴斿嚱鏁? 鐢辫鏃跺櫒瑙﹀彂锛岃皟搴﹁Е鎽稿睆宸ヤ綔鍑芥暟杩愯锛涗箣鍚庨噸鏂拌鏃?鍙傛暟锛? timer锛氬嚱鏁板叧鑱旂殑璁℃椂鍣?
return锛? 璁℃椂鍣ㄥ伐浣滄ā寮忥紝HRTIMER_NORESTART琛ㄧず涓嶉渶瑕佽嚜鍔ㄩ噸鍚?********************************************************/
static enum hrtimer_restart goodix_ts_timer_func(struct hrtimer *timer)
{
struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);
queue_work(goodix_wq, &ts->work);
hrtimer_start(&ts->timer, ktime_set(0, (POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
/*******************************************************
鍔熻兘锛? 涓柇鍝嶅簲鍑芥暟
鐢变腑鏂Е鍙戯紝璋冨害瑙︽懜灞忓鐞嗗嚱鏁拌繍琛?鍙傛暟锛? timer锛氬嚱鏁板叧鑱旂殑璁℃椂鍣?
return锛? 璁℃椂鍣ㄥ伐浣滄ā寮忥紝HRTIMER_NORESTART琛ㄧず涓嶉渶瑕佽嚜鍔ㄩ噸鍚?********************************************************/
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
struct goodix_ts_data *ts = dev_id;
//printk(KERN_INFO"-------------------ts_irq_handler------------------\n");
disable_irq_nosync(ts->client->irq);
queue_work(goodix_wq, &ts->work);
return IRQ_HANDLED;
}
/*******************************************************
鍔熻兘锛? 绠$悊GT801鐨勭數婧愶紝鍏佽GT801 PLUS杩涘叆鐫$湢鎴栧皢鍏跺敜閱?鍙傛暟锛? on: 0琛ㄧず浣胯兘鐫$湢锛?涓哄敜閱?return锛? 鏄惁璁剧疆鎴愬姛锛?涓烘垚鍔? 閿欒鐮侊細-1涓篿2c閿欒锛?2涓篏PIO閿欒锛?EINVAL涓哄弬鏁皁n閿欒
********************************************************/
//#if defined(INT_PORT)
static int goodix_ts_power(struct goodix_ts_data * ts, int on)
{
int ret = -1;
int retry = 50;//zsf add
unsigned char i2c_control_buf[3] = {0x06,0x92,0x01}; //suspend cmd
#ifdef INT_PORT
if(ts != NULL && !ts->use_irq)
return -2;
#endif
switch(on)
{
case 0:
i2c_pre_cmd(ts); //must
ret = i2c_write_bytes(ts->client, i2c_control_buf, 3);
printk(KERN_INFO"Send suspend cmd\n");
if(ret > 0) //failed
ret = 0;
i2c_end_cmd(ts); //must
return ret;
case 1:
//zsf add start
sndpw_retry:
retry--;
//zsf add end
#if 0 // #ifdef INT_PORT //suggest use INT PORT to wake up !!!
gpio_direction_output(gt818_gpio_tp_irq, 0);
msleep(20);
gpio_direction_output(gt818_gpio_tp_irq, 1);
msleep(20);
gpio_direction_output(gt818_gpio_tp_irq, 0);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
//if(ts->use_irq)
// s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port as interrupt port
//else
gpio_direction_input(gt818_gpio_tp_irq);
#else
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
#endif
msleep(40);
ret = goodix_init_panel(ts);
if(ret < 0&& retry>0)//zsf add
goto sndpw_retry;
return ret;
default:
printk(KERN_DEBUG "%s: Cant't support this command.", s3c_ts_name);
return -EINVAL;
}
}
/*******************************************************
鍔熻兘锛? 瑙︽懜灞忔帰娴嬪嚱鏁? 鍦ㄦ敞鍐岄┍鍔ㄦ椂璋冪敤(瑕佹眰瀛樺湪瀵瑰簲鐨刢lient)锛? 鐢ㄤ簬IO,涓柇绛夎祫婧愮敵璇凤紱璁惧娉ㄥ唽锛涜Е鎽稿睆鍒濆鍖栫瓑宸ヤ綔
鍙傛暟锛? client锛氬緟椹卞姩鐨勮澶囩粨鏋勪綋
id锛氳澶嘔D
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//TODO:鍦ㄦ祴璇曞け璐ュ悗闇€瑕侀噴鏀総s
int ret = 0;
int retry=0;
//unsigned short version_temp = 0;
unsigned char update_path[1] = {0};
#if defined(NO_DEFAULT_ID) && defined(INT_PORT)
uint8_t goodix_id[3] = {0,0xff,0};
#endif
char test_data = 1;
struct goodix_ts_data *ts;
struct goodix_i2c_rmi_platform_data *pdata;
dev_dbg(&client->dev,"Install touch driver.\n");
//Check I2C function
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
dev_err(&client->dev, "Must have I2C_FUNC_I2C.\n");
ret = -ENODEV;
goto err_check_functionality_failed;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
ret = -ENOMEM;
goto err_alloc_data_failed;
}
i2c_connect_client = client; //used by Guitar_Update
#ifdef INT_PORT
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
#endif
#if defined(NO_DEFAULT_ID) && defined(INT_PORT)
for(retry=0;retry < 3; retry++)
{
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(20);
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
break;
}
if(ret <= 0)
{
gpio_direction_output(gt818_gpio_tp_irq,0);
msleep(1);
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(20);
gpio_direction_input(gt818_gpio_tp_rst);
for(retry=0;retry < 80; retry++)
{
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
{
msleep(10);
ret =i2c_read_bytes(client, goodix_id, 3); //Test I2C connection.
if (ret > 0)
{
if(goodix_id[2] == 0x55)
{
gpio_direction_output(gt818_gpio_tp_irq,1);
msleep(1);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
msleep(10);
break;
}
}
}
}
}
#endif
//while(1)
for(retry=0;retry < 3; retry++)
{
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(1);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(20);
//gt818_ts_reset();
ret =i2c_write_bytes(client, &test_data, 1); //Test I2C connection.
if (ret > 0)
break;
}
if(ret <= 0)
{
dev_err(&client->dev, "Warnning: I2C communication might be ERROR ret=%d!\n", ret);
goto err_i2c_failed;
}
INIT_WORK(&ts->work, goodix_ts_work_func); //init work_struct
ts->client = client;
i2c_set_clientdata(client, ts);
pdata = client->dev.platform_data;
#ifdef AUTO_UPDATE_GT818
i2c_pre_cmd(ts);
goodix_read_version(ts);
i2c_end_cmd(ts);
ret = gt818_downloader( ts, goodix_gt818_firmware, update_path);
if(ret < 0)
{
dev_err(&client->dev, "Warnning: GT818 update might be ERROR!\n");
//goto err_input_dev_alloc_failed;
}
#endif
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
dev_dbg(&client->dev,"goodix_ts_probe: Failed to allocate input device\n");
goto err_input_dev_alloc_failed;
}
ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); // absolute coor (x,y)
#ifdef H***E_TOUCH_KEY
for(retry = 0; retry < MAX_KEY_NUM; retry++)
{
input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
}
#endif
input_set_abs_params(ts->input_dev, ABS_X, 0, TOUCH_MAX_WIDTH, 0, 0);
input_set_abs_params(ts->input_dev, ABS_Y, 0, TOUCH_MAX_HEIGHT, 0, 0);
input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
#ifdef GOODIX_MULTI_TOUCH
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, TOUCH_MAX_WIDTH, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, TOUCH_MAX_HEIGHT, 0, 0);
#endif
sprintf(ts->phys, "input/ts");
ts->input_dev->name = s3c_ts_name;
ts->input_dev->phys = ts->phys;
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0xDEAD;
ts->input_dev->id.product = 0xBEEF;
ts->input_dev->id.version = 10427; //screen firmware version
ret = input_register_device(ts->input_dev);
if (ret) {
dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
goto err_input_register_device_failed;
}
ts->bad_data = 0;
// finger_list.length = 0;
#ifdef INT_PORT
client->irq=gt818_gpio_tp_irq_int_num; //If not defined in client
if (client->irq)
{
ret = gpio_request(gt818_gpio_tp_irq, "TS_INT"); //Request IO
if (ret < 0)
{
dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)gt818_gpio_tp_irq,ret);
goto err_gpio_request_failed;
}
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE); //ret > 0 ?
//s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port function
#if INT_TRIGGER==1
#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_RISING
#elif INT_TRIGGER==0
#define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_FALLING
// #elif INT_TRIGGER==2
// #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_LOW
// #elif INT_TRIGGER==3
// #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_LEVEL_HIGH
#endif
ret = request_irq(client->irq, goodix_ts_irq_handler , GT801_PLUS_IRQ_TYPE,
client->name, ts);
if (ret != 0) {
dev_err(&client->dev,"Cannot allocate ts INT!ERRNO:%d\n", ret);
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
goto err_gpio_request_failed;
}
else
{
disable_irq(client->irq);
ts->use_irq = 1;
dev_dbg(&client->dev,"Reques EIRQ %d succesd on GPIO:%d\n",gt818_gpio_tp_irq_int_num,gt818_gpio_tp_irq);
}
}
#endif
err_gpio_request_failed:
if (!ts->use_irq)
{
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = goodix_ts_timer_func;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
i2c_pre_cmd(ts);
msleep(2);
for(retry=0; retry<3; retry++)
{
ret=goodix_init_panel(ts);
dev_info(&client->dev,"the config ret is :%d\n",ret);
msleep(2);
if(ret != 0) //Initiall failed
continue;
else
break;
}
if(ret != 0) {
ts->bad_data=1;
goto err_init_godix_ts;
}
if(ts->use_irq)
enable_irq(client->irq);
ts->power = goodix_ts_power;
goodix_read_version(ts);
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ts->early_suspend.suspend = goodix_ts_early_suspend;
ts->early_suspend.resume = goodix_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
goodix_proc_entry = create_proc_entry("goodix-update", 0666, NULL);
if(goodix_proc_entry == NULL)
{
dev_info(&client->dev, "Couldn't create proc entry!\n");
ret = -ENOMEM;
goto err_create_proc_entry;
}
else
{
dev_info(&client->dev, "Create proc entry success!\n");
goodix_proc_entry->write_proc = goodix_update_write;
goodix_proc_entry->read_proc = goodix_update_read;
//goodix_proc_entry->owner =THIS_MODULE;
}
#endif
i2c_end_cmd(ts);
dev_info(&client->dev,"Start %s in %s mode\n",
ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
return 0;
err_init_godix_ts:
i2c_end_cmd(ts);
if(ts->use_irq)
{
ts->use_irq = 0;
free_irq(client->irq,ts);
#ifdef INT_PORT
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
#endif
}
else
hrtimer_cancel(&ts->timer);
err_input_register_device_failed:
input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
i2c_set_clientdata(client, NULL);
err_i2c_failed:
kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
err_create_proc_entry:
return ret;
}
/*******************************************************
鍔熻兘锛? 椹卞姩璧勬簮閲婃斁
鍙傛暟锛? client锛氳澶囩粨鏋勪綋
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&ts->early_suspend);
#endif
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
remove_proc_entry("goodix-update", NULL);
#endif
if (ts && ts->use_irq)
{
#ifdef INT_PORT
gpio_direction_input(gt818_gpio_tp_irq);
gpio_free(gt818_gpio_tp_irq);
#endif
free_irq(client->irq, ts);
}
else if(ts)
hrtimer_cancel(&ts->timer);
dev_notice(&client->dev,"The driver is removing...\n");
i2c_set_clientdata(client, NULL);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
//鍋滅敤璁惧
static int goodix_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->use_irq)
disable_irq(client->irq);
else
hrtimer_cancel(&ts->timer);
//ret = cancel_work_sync(&ts->work);
//if(ret && ts->use_irq)
//enable_irq(client->irq);
if (ts->power) { /* 蹇呴』鍦ㄥ彇娑坵ork鍚庡啀鎵ц锛岄伩鍏嶅洜GPIO瀵艰嚧鍧愭爣澶勭悊浠g爜姝诲惊鐜?*/
ret = ts->power(ts, 0);
if (ret < 0)
printk(KERN_ERR "goodix_ts_resume power off failed\n");
}
return 0;
}
//閲嶆柊鍞ら啋
static int goodix_ts_resume(struct i2c_client *client)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if (ts->power) {
ret = ts->power(ts, 1);
if (ret < 0)
printk(KERN_ERR "goodix_ts_resume power on failed\n");
}
if (ts->use_irq)
enable_irq(client->irq);
else
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_suspend(ts->client, PMSG_SUSPEND);
}
static void goodix_ts_late_resume(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_resume(ts->client);
}
#endif
//******************************Begin of firmware update surpport*******************************
#ifdef CONFIG_TOUCHSCREEN_GOODIX_IAP
/*
static int update_read_version(struct goodix_ts_data *ts, char **version)
{
int ret = -1, count = 0;
//unsigned char version_data[18];
char *version_data;
char *p;
*version = (char *)vmalloc(5);
version_data = *version;
if(!version_data)
return -ENOMEM;
p = version_data;
memset(version_data, 0, sizeof(version_data));
version_data[0]=0x07;
version_data[1]=0x17;
ret=i2c_read_bytes(ts->client,version_data, 4);
if (ret < 0)
return ret;
version_data[5]='\0';
if(*p == '\0')
return 0;
do
{
if((*p > 122) || (*p < 48 && *p != 32) || (*p >57 && *p < 65)
||(*p > 90 && *p < 97 && *p != '_')) //check illeqal character
count++;
}while(*++p != '\0' );
if(count > 2)
return 0;
else
return 1;
}
*/
/**
@brief CRC cal proc,include : Reflect,init_crc32_table,GenerateCRC32
@param global var oldcrc32
@return states
*/
static unsigned int Reflect(unsigned long int ref, char ch)
{
unsigned int value=0;
int i;
for(i = 1; i < (ch + 1); i++)
{
if(ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
/*---------------------------------------------------------------------------------------------------------*/
/* CRC Check Program INIT */
/*---------------------------------------------------------------------------------------------------------*/
/*
static void init_crc32_table(void)
{
unsigned int temp;
unsigned int t1,t2;
unsigned int flag;
int i,j;
for(i = 0; i <= 0xFF; i++)
{
temp=Reflect(i, 8);
crc32_table[i]= temp<< 24;
for (j = 0; j < 8; j++)
{
flag=crc32_table[i]&0x80000000;
t1=(crc32_table[i] << 1);
if(flag==0)
t2=0;
else
t2=ulPolynomial;
crc32_table[i] =t1^t2 ;
}
crc32_table[i] = Reflect(crc32_table[i], 32);
}
}
*/
/*---------------------------------------------------------------------------------------------------------*/
/* CRC main Program */
/*---------------------------------------------------------------------------------------------------------*/
/*
static void GenerateCRC32(unsigned char * buf, unsigned int len)
{
unsigned int i;
unsigned int t;
for (i = 0; i != len; ++i)
{
t = (oldcrc32 ^ buf[i]) & 0xFF;
oldcrc32 = ((oldcrc32 >> 8) & 0xFFFFFF) ^ crc32_table[t];
}
}
*/
static struct file * update_file_open(char * path, mm_segment_t * old_fs_p)
{
struct file * filp = NULL;
int errno = -1;
filp = filp_open(path, O_RDONLY, 0644);
if(!filp || IS_ERR(filp))
{
if(!filp)
errno = -ENOENT;
else
errno = PTR_ERR(filp);
printk(KERN_ERR "The update file for Guitar open error.\n");
return NULL;
}
*old_fs_p = get_fs();
set_fs(get_ds());
filp->f_op->llseek(filp,0,0);
return filp ;
}
static void update_file_close(struct file * filp, mm_segment_t old_fs)
{
set_fs(old_fs);
if(filp)
filp_close(filp, NULL);
}
static int update_get_flen(char * path)
{
struct file * file_ck = NULL;
mm_segment_t old_fs;
int length ;
file_ck = update_file_open(path, &old_fs);
if(file_ck == NULL)
return 0;
length = file_ck->f_op->llseek(file_ck, 0, SEEK_END);
//printk("File length: %d\n", length);
if(length < 0)
length = 0;
update_file_close(file_ck, old_fs);
return length;
}
/*
static int update_file_check(char * path)
{
unsigned char buffer[64] = { 0 } ;
struct file * file_ck = NULL;
mm_segment_t old_fs;
int count, ret, length ;
file_ck = update_file_open(path, &old_fs);
if(path != NULL)
printk("File Path:%s\n", path);
if(file_ck == NULL)
return -ERROR_NO_FILE;
length = file_ck->f_op->llseek(file_ck, 0, SEEK_END);
#ifdef GUITAR_MESSAGE
printk(KERN_INFO "gt801 update: File length: %d\n",length);
#endif
if(length <= 0 || (length%4) != 0)
{
update_file_close(file_ck, old_fs);
return -ERROR_FILE_TYPE;
}
//set file point to the begining of the file
file_ck->f_op->llseek(file_ck, 0, SEEK_SET);
oldcrc32 = 0xFFFFFFFF;
init_crc32_table();
while(length > 0)
{
ret = file_ck->f_op->read(file_ck, buffer, sizeof(buffer), &file_ck->f_pos);
if(ret > 0)
{
for(count = 0; count < ret; count++)
GenerateCRC32(&buffer[count],1);
}
else
{
update_file_close(file_ck, old_fs);
return -ERROR_FILE_READ;
}
length -= ret;
}
oldcrc32 = ~oldcrc32;
#ifdef GUITAR_MESSAGE
printk("CRC_Check: %u\n", oldcrc32);
#endif
update_file_close(file_ck, old_fs);
return 1;
}
unsigned char wait_slave_ready(struct goodix_ts_data *ts, unsigned short *timeout)
{
unsigned char i2c_state_buf[2] = {ADDR_STA, UNKNOWN_ERROR};
int ret;
while(*timeout < MAX_TIMEOUT)
{
ret = i2c_read_bytes(ts->client, i2c_state_buf, 2);
if(ret <= 0)
return ERROR_I2C_TRANSFER;
if(i2c_state_buf[1] & SL***E_READY)
{
return 1;
}
msleep(1);
*timeout += 5;
}
return 0;
}
*/
static int goodix_update_write(struct file *filp, const char __user *buff, unsigned long len, void *data)
{
unsigned char cmd[120];
int ret = -1;
int retry = 0;
static unsigned char update_path[60];
struct goodix_ts_data *ts;
ts = i2c_get_clientdata(i2c_connect_client);
if(ts==NULL)
{
printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
return 0;
}
//printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
if(copy_from_user(&cmd, buff, len))
{
printk(KERN_INFO"goodix write to kernel via proc
file!@@@@@@\n");
return -EFAULT;
}
//printk(KERN_INFO"Write cmd is:%d,write len is:%ld\n",cmd[0], len);
switch(cmd[0])
{
case APK_UPDATE_TP:
printk(KERN_INFO"Write cmd is:%d,cmd arg is:%s,write len is:%ld\n",cmd[0], &cmd[1], len);
memset(update_path, 0, 60);
strncpy(update_path, cmd+1, 60);
ret = gt818_downloader( ts, goodix_gt818_firmware, update_path);
if(ret < 0)
{
printk(KERN_INFO"Warnning: GT818 update might be ERROR!\n");
return 0;
}
i2c_pre_cmd(ts);
msleep(2);
for(retry=0; retry<3; retry++)
{
ret=goodix_init_panel(ts);
printk(KERN_INFO"the config ret is :%d\n",ret);
msleep(2);
if(ret != 0) //Initiall failed
continue;
else
break;
}
//if(ts->use_irq)
// s3c_gpio_cfgpin(gt818_gpio_tp_irq, int_cfg_num); //Set IO port as interrupt port
// else
gpio_direction_input(gt818_gpio_tp_irq);
i2c_end_cmd(ts);
if(ret != 0)
{
ts->bad_data=1;
return 1;
}
return 1;
case APK_READ_FUN: //functional command
if(cmd[1] == CMD_READ_VER)
{
printk(KERN_INFO"Read version!\n");
ts->read_mode = MODE_RD_VER;
}
else if(cmd[1] == CMD_READ_CFG)
{
printk(KERN_INFO"Read config info!\n");
ts->read_mode = MODE_RD_CFG;
}
return 1;
case APK_WRITE_CFG:
printk(KERN_INFO"Begin write config info!Config length:%d\n",cmd[1]);
i2c_pre_cmd(ts);
ret = i2c_write_bytes(ts->client, cmd+2, cmd[1]+2);
i2c_end_cmd(ts);
if(ret != 1)
{
printk("Write Config failed!return:%d\n",ret);
return -1;
}
return 1;
default:
return 0;
}
return 0;
}
static int goodix_update_read( char *page, char **start, off_t off, int count, int *eof, void *data )
{
int ret = -1;
struct goodix_ts_data *ts;
int len = 0;
unsigned char read_data[360] = {80, };
ts = i2c_get_clientdata(i2c_connect_client);
if(ts==NULL)
return 0;
printk("___READ__\n");
if(ts->read_mode == MODE_RD_VER) //read version data
{
i2c_pre_cmd(ts);
ret = goodix_read_version(ts);
i2c_end_cmd(ts);
if(ret <= 0)
{
printk(KERN_INFO"Read version data failed!\n");
return 0;
}
read_data[1] = (char)(ts->version&0xff);
read_data[0] = (char)((ts->version>>8)&0xff);
printk(KERN_INFO"Gt818 ROM version is:%x%x\n", read_data[0],read_data[1]);
memcpy(page, read_data, 2);
*eof = 1;
return 2;
}
else if(ts->read_mode == MODE_RD_CFG)
{
read_data[0] = 0x06;
read_data[1] = 0xa2; // cfg start address
printk("read config addr is:%x,%x\n", read_data[0],read_data[1]);
len = 106;
i2c_pre_cmd(ts);
ret = i2c_read_bytes(ts->client, read_data, len+2);
i2c_end_cmd(ts);
if(ret <= 0)
{
printk(KERN_INFO"Read config info failed!\n");
return 0;
}
memcpy(page, read_data+2, len);
return len;
}
return len;
}
#endif
//********************************************************************************************
static u8 is_equal( u8 *src , u8 *dst , int len )
{
int i;
for( i = 0 ; i < len ; i++ )
{
//printk(KERN_INFO"[%02X:%02X]\n", src[i], dst[i]);
}
for( i = 0 ; i < len ; i++ )
{
if ( src[i] != dst[i] )
{
return 0;
}
}
return 1;
}
static u8 gt818_nvram_store( struct goodix_ts_data *ts )
{
int ret;
int i;
u8 inbuf[3] = {REG_NVRCS_H,REG_NVRCS_L,0};
//u8 outbuf[3] = {};
ret = i2c_read_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
{
return 0;
}
if ( ( inbuf[2] & BIT_NVRAM_LOCK ) == BIT_NVRAM_LOCK )
{
return 0;
}
inbuf[2] = (1<<BIT_NVRAM_STROE); //store command
for ( i = 0 ; i < 300 ; i++ )
{
ret = i2c_write_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
break;
}
return ret;
}
static u8 gt818_nvram_recall( struct goodix_ts_data *ts )
{
int ret;
u8 inbuf[3] = {REG_NVRCS_H,REG_NVRCS_L,0};
ret = i2c_read_bytes( ts->client, inbuf, 3 );
if ( ret < 0 )
{
return 0;
}
if ( ( inbuf[2]&BIT_NVRAM_LOCK) == BIT_NVRAM_LOCK )
{
return 0;
}
inbuf[2] = ( 1 << BIT_NVRAM_RECALL ); //recall command
ret = i2c_write_bytes( ts->client , inbuf, 3);
return ret;
}
static int gt818_reset( struct goodix_ts_data *ts )
{
int ret = 1;
u8 retry;
unsigned char outbuf[3] = {0,0xff,0};
unsigned char inbuf[3] = {0,0xff,0};
//outbuf[1] = 1;
gpio_direction_output(gt818_gpio_tp_rst,0);
msleep(20);
gpio_direction_input(gt818_gpio_tp_rst);
msleep(100);
for(retry=0;retry < 80; retry++)
{
ret =i2c_write_bytes(ts->client, inbuf, 0); //Test I2C connection.
if (ret > 0)
{
msleep(10);
ret =i2c_read_bytes(ts->client, inbuf, 3); //Test I2C connection.
if (ret > 0)
{
if(inbuf[2] == 0x55)
{
ret =i2c_write_bytes(ts->client, outbuf, 3);
msleep(10);
break;
}
}
}
}
printk(KERN_INFO"Detect address %0X\n", ts->client->addr);
//msleep(500);
return ret;
}
static int gt818_set_address_2( struct goodix_ts_data *ts )
{
unsigned char inbuf[3] = {0,0,0};
int i;
for ( i = 0 ; i < 12 ; i++ )
{
if ( i2c_read_bytes( ts->client, inbuf, 3) )
{
printk(KERN_INFO"Got response\n");
return 1;
}
printk(KERN_INFO"wait for retry\n");
msleep(50);
}
return 0;
}
static u8 gt818_update_firmware( u8 *nvram, u16 length, struct goodix_ts_data *ts)
{
u8 ret,err,retry_time,i;
u16 cur_code_addr;
u16 cur_frame_num, total_frame_num, cur_frame_len;
u32 gt80x_update_rate;
unsigned char i2c_data_buf[PACK_SIZE+2] = {0,}; //私戮莼潞麓鐖? unsigned char i2c_chk_data_buf[PACK_SIZE+2] = {0,}; //私戮莼潞麓鐖? err = 0;
if( length > NVRAM_LEN - NVRAM_BOOT_SECTOR_LEN )
{
printk(KERN_INFO"length too big %d %d\n", length, NVRAM_LEN - NVRAM_BOOT_SECTOR_LEN );
return 0;
}
total_frame_num = ( length + PACK_SIZE - 1) / PACK_SIZE;
//gt80x_update_sta = _UPDATING;
gt80x_update_rate = 0;
for( cur_frame_num = 0 ; cur_frame_num < total_frame_num ; cur_frame_num++ )
{
retry_time = 5;
cur_code_addr = NVRAM_UPDATE_START_ADDR + cur_frame_num * PACK_SIZE;
i2c_data_buf[0] = (cur_code_addr>>8)&0xff;
i2c_data_buf[1] = cur_code_addr&0xff;
i2c_chk_data_buf[0] = i2c_data_buf[0];
i2c_chk_data_buf[1] = i2c_data_buf[1];
if( cur_frame_num == total_frame_num - 1 )
{
cur_frame_len = length - cur_frame_num * PACK_SIZE;
}
else
{
cur_frame_len = PACK_SIZE;
}
//strncpy(&i2c_data_buf[2], &nvram[cur_frame_num*PACK_SIZE], cur_frame_len);
for(i=0;i<cur_frame_len;i++)
{
i2c_data_buf[2+i] = nvram[cur_frame_num*PACK_SIZE+i];
}
do
{
err = 0;
//ret = gt818_i2c_write( guitar_i2c_address, cur_code_addr, &nvram[cur_frame_num*I2C_FRAME_MAX_LENGTH], cur_frame_len );
ret = i2c_write_bytes(ts->client, i2c_data_buf, (cur_frame_len+2));
if ( ret <= 0 )
{
printk(KERN_INFO"write fail\n");
err = 1;
}
ret = i2c_read_bytes(ts->client, i2c_chk_data_buf, (cur_frame_len+2));
// ret = gt818_i2c_read( guitar_i2c_address, cur_code_addr, inbuf, cur_frame_len);
if ( ret <= 0 )
{
printk(KERN_INFO"read fail\n");
err = 1;
}
if( is_equal( &i2c_data_buf[2], &i2c_chk_data_buf[2], cur_frame_len ) == 0 )
{
printk(KERN_INFO"not equal\n");
err = 1;
}
} while ( err == 1 && (--retry_time) > 0 );
if( err == 1 )
{
break;
}
gt80x_update_rate = ( cur_frame_num + 1 )*128/total_frame_num;
}
if( err == 1 )
{
printk(KERN_INFO"write nvram fail\n");
return 0;
}
ret = gt818_nvram_store(ts);
msleep( 20 );
if( ret == 0 )
{
printk(KERN_INFO"nvram store fail\n");
return 0;
}
ret = gt818_nvram_recall(ts);
msleep( 20 );
if( ret == 0 )
{
printk(KERN_INFO"nvram recall fail\n");
return 0;
}
for ( cur_frame_num = 0 ; cur_frame_num < total_frame_num ; cur_frame_num++ ) // read out all the code
{
cur_code_addr = NVRAM_UPDATE_START_ADDR + cur_frame_num*PACK_SIZE;
retry_time=5;
i2c_chk_data_buf[0] = (cur_code_addr>>8)&0xff;
i2c_chk_data_buf[1] = cur_code_addr&0xff;
if ( cur_frame_num == total_frame_num-1 )
{
cur_frame_len = length - cur_frame_num*PACK_SIZE;
}
else
{
cur_frame_len = PACK_SIZE;
}
do
{
err = 0;
//ret = gt818_i2c_read( guitar_i2c_address, cur_code_addr, inbuf, cur_frame_len);
ret = i2c_read_bytes(ts->client, i2c_chk_data_buf, (cur_frame_len+2));
if ( ret == 0 )
{
err = 1;
}
if( is_equal( &nvram[cur_frame_num*PACK_SIZE], &i2c_chk_data_buf[2], cur_frame_len ) == 0 )
{
err = 1;
}
} while ( err == 1 && (--retry_time) > 0 );
if( err == 1 )
{
break;
}
gt80x_update_rate = 127 + ( cur_frame_num + 1 )*128/total_frame_num;
}
gt80x_update_rate = 255;
//gt80x_update_sta = _UPDATECHKCODE;
if( err == 1 )
{
printk(KERN_INFO"nvram validate fail\n");
return 0;
}
//往0X00FF写0XCC表示烧录结束
i2c_chk_data_buf[0] = 0xff;
i2c_chk_data_buf[1] = 0x00;
i2c_chk_data_buf[2] = 0x0;
ret = i2c_write_bytes(ts->client, i2c_chk_data_buf, 3);
if( ret <= 0 )
{
printk(KERN_INFO"nvram validate fail\n");
return 0;
}
return 1;
}
static u8 gt818_update_proc( u8 *nvram, u16 length, struct goodix_ts_data *ts )
{
u8 ret;
u8 error = 0;
//struct tpd_info_t tpd_info;
GT818_SET_INT_PIN( 0 );
msleep( 20 );
ret = gt818_reset(ts);
if ( ret < 0 )
{
error = 1;
printk(KERN_INFO"reset fail\n");
goto end;
}
ret = gt818_set_address_2( ts );
if ( ret == 0 )
{
error = 1;
printk(KERN_INFO"set address fail\n");
goto end;
}
ret = gt818_update_firmware( nvram, length, ts);
if ( ret == 0 )
{
error=1;
printk(KERN_INFO"firmware update fail\n");
goto end;
}
end:
//GT818_SET_INT_PIN( 1 );
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
msleep( 500 );
ret = gt818_reset(ts);
if ( ret < 0 )
{
error=1;
printk(KERN_INFO"final reset fail\n");
goto end;
}
if ( error == 1 )
{
return 0;
}
i2c_pre_cmd(ts);
while(goodix_read_version(ts)<0);
i2c_end_cmd(ts);
return 1;
}
static int gt818_downloader( struct goodix_ts_data *ts, unsigned char * data, unsigned char * path)
{
struct tpd_firmware_info_t *fw_info = (struct tpd_firmware_info_t *)data;
int i;
unsigned short checksum = 0;
unsigned char *data_ptr = &(fw_info->data);
int retry = 0,ret;
int err = 0;
struct file * file_data = NULL;
mm_segment_t old_fs;
//unsigned int rd_len;
unsigned int file_len = 0;
//unsigned char i2c_data_buf[PACK_SIZE] = {0,};
const int MAGIC_NUMBER_1 = 0x4D454449;
const int MAGIC_NUMBER_2 = 0x4154454B;
if(path[0] == 0)
{
printk(KERN_INFO"%s\n", __func__ );
printk(KERN_INFO"magic number 0x%08X 0x%08X\n", fw_info->magic_number_1, fw_info->magic_number_2 );
printk(KERN_INFO"magic number 0x%08X 0x%08X\n", MAGIC_NUMBER_1, MAGIC_NUMBER_2 );
printk(KERN_INFO"current version 0x%04X, target verion 0x%04X\n", ts->version, fw_info->version );
printk(KERN_INFO"size %d\n", fw_info->length );
printk(KERN_INFO"checksum %d\n", fw_info->checksum );
if ( fw_info->magic_number_1 != MAGIC_NUMBER_1 && fw_info->magic_number_2 != MAGIC_NUMBER_2 )
{
printk(KERN_INFO"Magic number not match\n");
err = 0;
goto exit_downloader;
}
if(((ts->version&0xff)> 0x99)||((ts->version&0xff) < 0x4a))
{
goto update_start;
}
if ( ts->version >= fw_info->version )
{
printk(KERN_INFO"No need to upgrade\n");
err = 0;
goto exit_downloader;
}
if ( get_chip_version( ts->version ) != get_chip_version( fw_info->version ) )
{
printk(KERN_INFO"Chip version incorrect");
err = 0;
goto exit_downloader;
}
update_start:
for ( i = 0 ; i < fw_info->length ; i++ )
checksum += data_ptr[i];
checksum = checksum%0xFFFF;
if ( checksum != fw_info->checksum )
{
printk(KERN_INFO"Checksum not match 0x%04X\n", checksum);
err = 0;
goto exit_downloader;
}
}
else
{
printk(KERN_INFO"Write cmd arg is:\n");
file_data = update_file_open(path, &old_fs);
printk(KERN_INFO"Write cmd arg is\n");
if(file_data == NULL) //file_data has been opened at the last time
{
err = -1;
goto exit_downloader;
}
file_len = (update_get_flen(path))-2;
printk(KERN_INFO"current length:%d\n", file_len);
ret = file_data->f_op->read(file_data, &data_ptr[0], file_len, &file_data->f_pos);
if(ret <= 0)
{
err = -1;
goto exit_downloader;
}
update_file_close(file_data, old_fs);
}
printk(KERN_INFO"STEP_0:\n");
//adapter = client->adapter;
gpio_free(gt818_gpio_tp_irq);
ret = gpio_request(gt818_gpio_tp_irq, "TS_INT"); //Request IO
if (ret < 0)
{
printk(KERN_INFO"Failed to request GPIO:%d, ERRNO:%d\n",(int)gt818_gpio_tp_irq,ret);
err = -1;
goto exit_downloader;
}
printk(KERN_INFO"STEP_1:\n");
err = -1;
while ( retry < 3 )
{
ret = gt818_update_proc( data_ptr, fw_info->length, ts);
if(ret == 1)
{
err = 1;
break;
}
retry++;
}
exit_downloader:
//mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
// mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ONE);
// gpio_direction_output(gt818_gpio_tp_irq,1);
// msleep(1);
gpio_free(gt818_gpio_tp_irq);
//s3c_gpio_setpull(gt818_gpio_tp_irq, S3C_GPIO_PULL_NONE);
return err;
}
//******************************End of firmware update surpport*******************************
//鍙敤浜庤椹卞姩鐨?璁惧鍚嶁€旇澶嘔D 鍒楄〃
//only one client
static const struct i2c_device_id goodix_ts_id[] = {
{ GOODIX_I2C_NAME, 0 },
{ }
};
//璁惧椹卞姩缁撴瀯浣?static struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = goodix_ts_suspend,
.resume = goodix_ts_resume,
#endif
.id_table = goodix_ts_id,
.driver = {
.name = GOODIX_I2C_NAME,
.owner = THIS_MODULE,
},
};
/*******************************************************
鍔熻兘锛? 椹卞姩鍔犺浇鍑芥暟
return锛? 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц
********************************************************/
static int __devinit goodix_ts_init(void)
{
// int ret;
printk("wax->%s\n",__FUNCTION__);
goodix_wq = create_workqueue("goodix_wq"); //create a work queue and worker thread
if (!goodix_wq) {
printk(KERN_ALERT "creat workqueue faiked\n");
return -ENOMEM;
}
printk("%s\n", __func__);
gt818_gpio_tp_irq_int_num=gt818_config_pins();
gt818_ts_setup.i2c_bus = 2;
gt818_ts_setup.i2c_address = GT818_TS_ADDR;
strcpy (gt818_ts_setup.type,GOODIX_I2C_NAME);
gt818_ts_setup.irq = gt818_gpio_tp_irq_int_num;
return gt818_sprd_add_i2c_device(>818_ts_setup, &goodix_ts_driver);
//ret=i2c_add_driver(&goodix_ts_driver);
//return ret;
}
/*******************************************************
鍔熻兘锛? 椹卞姩鍗歌浇鍑芥暟
鍙傛暟锛? client锛氳澶囩粨鏋勪綋
********************************************************/
static void __exit goodix_ts_exit(void)
{
printk(KERN_ALERT "Touchscreen driver of guitar exited.\n");
sprd_free_gpio_irq(gt818_gpio_tp_irq_int_num);
//i2c_del_driver(&goodix_ts_driver);
gt818_sprd_del_i2c_device(i2c_connect_client,&goodix_ts_driver);
if (goodix_wq)
destroy_workqueue(goodix_wq); //release our work queue
}
late_initcall(goodix_ts_init); //鏈€鍚庡垵濮嬪寲椹卞姩felix
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Driver");
MODULE_LICENSE("GPL");
相关文章推荐
- 触摸屏驱动分析
- linux子系统分析及触摸屏驱动浅析
- 触摸屏驱动分析(转载)
- 触摸屏驱动分析
- 触摸屏驱动分析
- Windows CE下触摸屏驱动实现的分析
- S3C2410驱动分析之触摸屏驱动
- 基于 mini2440 电阻式触摸屏(四):mini2440触摸屏驱动分析
- linux 触摸屏驱动分析
- ARM-Linux驱动-触摸屏驱动分析 .
- Linux下I2C接口触摸屏驱动分析
- 基于linux的mini2440触摸屏驱动分析
- linux触摸屏驱动分析,touchscreen, struct input_dev,基于TSC2007
- 基于 mini2440 电阻式触摸屏(四):mini2440触摸屏驱动分析
- Linux设备驱动工程师之路——触摸屏驱动s3c2410_ts.c分析
- 6410触摸屏驱动分析(s3c-ts.c)(Linux)(分析)
- Wince6.0 s3c6410触摸屏驱动分析
- S3C2410驱动分析之触摸屏驱动
- goodix触摸屏驱动调试(1)
- ARM-Linux驱动-触摸屏驱动分析