From: hhb Date: Sat, 18 Jun 2011 03:30:20 +0000 (+0800) Subject: rk29: touch screen : add gt818 driver X-Git-Tag: firefly_0821_release~10176^2~11 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=88682f92bae5ab56445d3c694833d425478c4c55;p=firefly-linux-kernel-4.4.55.git rk29: touch screen : add gt818 driver --- diff --git a/arch/arm/mach-rk29/board-rk29-phonesdk-rfkill.c b/arch/arm/mach-rk29/board-rk29-phonesdk-rfkill.c old mode 100755 new mode 100644 index 14367abd92fe..db39a9dad654 --- a/arch/arm/mach-rk29/board-rk29-phonesdk-rfkill.c +++ b/arch/arm/mach-rk29/board-rk29-phonesdk-rfkill.c @@ -138,9 +138,9 @@ static int bcm4329_set_block(void *data, bool blocked) if (false == blocked) { gpio_set_value(BT_GPIO_POWER, GPIO_HIGH); /* bt power on */ gpio_set_value(BT_GPIO_RESET, GPIO_LOW); - mdelay(20); + mdelay(200); gpio_set_value(BT_GPIO_RESET, GPIO_HIGH); /* bt reset deactive*/ - mdelay(20); + mdelay(200); #if BT_WAKE_HOST_SUPPORT btWakeupHostLock(); diff --git a/arch/arm/mach-rk29/board-rk29-phonesdk.c b/arch/arm/mach-rk29/board-rk29-phonesdk.c old mode 100755 new mode 100644 index 2d3bec8b6881..15fc4bff2953 --- a/arch/arm/mach-rk29/board-rk29-phonesdk.c +++ b/arch/arm/mach-rk29/board-rk29-phonesdk.c @@ -443,6 +443,7 @@ struct p1003_platform_data p1003_info = { }; #endif + #if defined(CONFIG_TOUCHSCREEN_GT801_IIC) #include "../../../drivers/input/touchscreen/gt801_ts.h" #define GT801_GPIO_INT RK29_PIN4_PD5 @@ -464,6 +465,28 @@ static struct gt801_platform_data gt801_info = { }; #endif + +#if defined(CONFIG_TOUCHSCREEN_GT818_IIC) +#include "../../../drivers/input/touchscreen/gt818_ts.h" +#define GT818_GPIO_INT RK29_PIN4_PD5 +#define GT818_GPIO_RESET RK29_PIN6_PC3 +static struct gt818_platform_data gt818_info = { + .model = 818, + .swap_xy = 0, + .x_min = 0, + .x_max = 480, + .y_min = 0, + .y_max = 800, + .gpio_reset = GT818_GPIO_RESET, + .gpio_reset_active_low = 0, + .gpio_pendown = GT818_GPIO_INT, + .pendown_iomux_name = GPIO4D5_CPUTRACECTL_NAME, + .resetpin_iomux_name = NULL, + .pendown_iomux_mode = GPIO4H_GPIO4D5, + .resetpin_iomux_mode = 0, +}; +#endif + #if defined(CONFIG_TOUCHSCREEN_ILI2102_IIC) #include "../../../drivers/input/touchscreen/ili2102_ts.h" #define GT801_GPIO_INT RK29_PIN4_PD5 @@ -1896,6 +1919,16 @@ static struct i2c_board_info __initdata board_i2c2_devices[] = { }, #endif +#if defined (CONFIG_TOUCHSCREEN_GT818_IIC) +{ + .type = "gt818_ts", + .addr = 0x5d, + .flags = 0, + .irq = RK29_PIN4_PD5, + .platform_data = >818_info, +}, +#endif + #if defined (CONFIG_TOUCHSCREEN_ILI2102_IIC) { .type = "ili2102_ts", @@ -2932,9 +2965,9 @@ static struct kobj_attribute rk29xx_virtual_keys_attr = { .name = "virtualkeys.gt801-touchscreen", #elif defined(CONFIG_TOUCHSCREEN_ILI2102_IIC) .name = "virtualkeys.ili2102-touchscreen", +#else + .name = "virtualkeys", #endif - - .mode = S_IRUGO, }, .show = &rk29xx_virtual_keys_show, @@ -3037,7 +3070,7 @@ static void __init machine_rk29_board_init(void) rk29sdk_init_wifi_mem(); #endif - rk29xx_virtual_keys_init(); +// rk29xx_virtual_keys_init(); } static void __init machine_rk29_fixup(struct machine_desc *desc, struct tag *tags, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 7e5f9e692722..9c659b72f389 100755 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -752,6 +752,9 @@ config TOUCHSCREEN_IT7260 config TOUCHSCREEN_GT801_IIC tristate "GT801_IIC based touchscreens" depends on I2C2_RK29 +config TOUCHSCREEN_GT818_IIC + tristate "GT818_IIC based touchscreens" + depends on I2C2_RK29 config D70_L3188A tristate "D70-L3188A based touchscreens" depends on I2C2_RK29 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7680d487fe67..46ac05c39355 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -54,7 +54,7 @@ obj-$(CONFIG_SINTEK_3FA16) += sintek_3FA16.o obj-$(CONFIG_EETI_EGALAX) += eeti_egalax_i2c.o obj-$(CONFIG_ATMEL_MXT224) += atmel_maxtouch.o obj-$(CONFIG_TOUCHSCREEN_GT801_IIC) += gt801_ts.o +obj-$(CONFIG_TOUCHSCREEN_GT818_IIC) += gt818_ts.o obj-$(CONFIG_TOUCHSCREEN_ILI2102_IIC) += ili2102_ts.o obj-$(CONFIG_D70_L3188A) += goodix_touch.o - diff --git a/drivers/input/touchscreen/gt818_ts.c b/drivers/input/touchscreen/gt818_ts.c new file mode 100644 index 000000000000..f3112b609942 --- /dev/null +++ b/drivers/input/touchscreen/gt818_ts.c @@ -0,0 +1,920 @@ +/* drivers/input/touchscreen/gt818_ts.c + * + * Copyright (C) 2011 Goodix, Inc. + * + * Author: Felix + * Date: 2011.04.28 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "gt818_ts.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 *gt818_ts_name = "Goodix Capacitive TouchScreen"; + +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; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void goodix_ts_early_suspend(struct early_suspend *h); +static void goodix_ts_late_resume(struct early_suspend *h); +#endif +//used by firmware update CRC +unsigned int oldcrc32 = 0xFFFFFFFF; +unsigned int crc32_table[256]; +unsigned int ulPolynomial = 0x04c11db7; + +#ifdef HAVE_TOUCH_KEY + const uint16_t gt818_key_array[]={ + KEY_MENU, + KEY_HOME, + KEY_BACK, + KEY_SEARCH + }; + #define MAX_KEY_NUM (sizeof(gt818_key_array)/sizeof(gt818_key_array[0])) +#endif + + + + +/******************************************************* +鍔熻兘锛� + 璇诲彇浠庢満鏁版嵁 + 姣忎釜璇绘搷浣滅敤涓ゆ潯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, u8 *buf, int len) +{ + struct i2c_msg msgs[2]; + int ret = -1; + //鍙戦�鍐欏湴鍧� + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; //鍐欐秷鎭� + msgs[0].len = 2; + msgs[0].buf = &buf[0]; + msgs[0].scl_rate = 400*1000; + msgs[0].udelay = client->udelay; + + //鎺ユ敹鏁版嵁 + msgs[1].addr = client->addr; + msgs[1].flags = client->flags | I2C_M_RD;//璇绘秷鎭� + msgs[1].len = len-2; + msgs[1].buf = &buf[2]; + msgs[1].scl_rate = 400*1000; + msgs[1].udelay = client->udelay; + + ret = i2c_transfer(client->adapter, msgs, 2); + if(ret < 0) + printk("%s:i2c_transfer fail =%d\n",__func__, ret); + 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,u8 *data,int len) +{ + struct i2c_msg msg; + int ret = -1; + //鍙戦�璁惧鍦板潃 + msg.addr = client->addr; + msg.flags = client->flags; //鍐欐秷鎭� + msg.len = len; + msg.buf = data; + msg.scl_rate = 400*1000; + msg.udelay = client->udelay; + ret = i2c_transfer(client->adapter, &msg, 1); + if(ret < 0) + printk("%s:i2c_transfer fail =%d\n",__func__, ret); + return ret; +} + +/******************************************************* +鍔熻兘锛� 鍙戦�鍓嶇紑鍛戒护 + + ts: client绉佹湁鏁版嵁缁撴瀯浣�return锛� + 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц +*******************************************************/ +static int i2c_pre_cmd(struct gt818_ts_data *ts) +{ + int ret; + u8 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 gt818_ts_data *ts) +{ + int ret; + u8 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; +} + + +/******************************************************* +鍔熻兘锛� Guitar鍒濆鍖栧嚱鏁帮紝鐢ㄤ簬鍙戦�閰嶇疆淇℃伅锛岃幏鍙栫増鏈俊鎭�鍙傛暟锛� ts: client绉佹湁鏁版嵁缁撴瀯浣�return锛� 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц +*******************************************************/ +static int goodix_init_panel(struct gt818_ts_data *ts) +{ + int ret = -1; + #if 1 + u8 config_info[] = { //Touch key devlop board + 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, + 0xE0,0x00,0xD0,0x00,0xC0,0x00,0xB0,0x00, + 0xA0,0x00,0x90,0x00,0x80,0x00,0x70,0x00, + 0x00,0x00,0x01,0x13,0x90,0x90,0x90,0x38, + 0x38,0x38,0x0F,0x0E,0x0A,0x42,0x30,0x08, + 0x03,0x00,MAX_FINGER_NUM,0x00,0x14,0x00,0x1C,0x01, + 0x01,0x3E,0x35,0x68,0x58,0x00,0x00,0x06, + 0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00, + 0x14,0x10,0x51,0x02,0x00,0x00,0x00,0x00, + 0x00,0x00,0x20,0x40,0x60,0x90,0x08,0x42, + 0x30,0x32,0x20,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01 + }; + #endif + + #if 0 + u8 config_info[] = { + 0x06,0xA2, + 0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E, + 0x10,0x12,0x70,0x00,0x60,0x00,0x80,0x00, + 0x50,0x00,0x90,0x00,0x40,0x00,0xA0,0x00, + 0x30,0x00,0xB0,0x00,0x20,0x00,0xC0,0x00, + 0x10,0x00,0xD0,0x00,0x00,0x00,0xE0,0x00, + 0x00,0x00,0x01,0x13,0x80,0x88,0x90,0x30, + 0x15,0x40,0x0F,0x0F,0x0A,0x60,0x3C,(0x00|((~(INT_TRIGGER<<3))&0x08)), + 0x03,0x60,MAX_FINGER_NUM,(TOUCH_MAX_WIDTH&0xff),(TOUCH_MAX_WIDTH>>8),(TOUCH_MAX_HEIGHT&0xff),(TOUCH_MAX_HEIGHT>>8),0x00, + 0x00,0x46,0x5A,0x5C,0x5E,0x00,0x00,0x03, + 0x19,0x05,0x00,0x00,0x00,0x00,0x00,0x00, + 0x14,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 + + ret = i2c_write_bytes(ts->client, config_info, (sizeof(config_info)/sizeof(config_info[0]))); + if (ret < 0) + return ret; + msleep(10); + return 0; + +} + + +/******************************************************* +鍔熻兘锛� 鑾峰彇鐗堟湰淇℃伅 +鍙傛暟锛� ts: client绉佹湁鏁版嵁缁撴瀯浣�return锛� 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц +*******************************************************/ +static int goodix_read_version(struct gt818_ts_data *ts) +{ + int ret; + u8 version_data[5] = {0}; //store touchscreen version infomation + memset(version_data, 0, 5); + version_data[0] = 0x07; + version_data[1] = 0x17; + 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]); + return 0; + +} + + +/******************************************************* +鍔熻兘锛� 瑙︽懜灞忓伐浣滃嚱鏁� 鐢变腑鏂Е鍙戯紝鎺ュ彈1缁勫潗鏍囨暟鎹紝鏍¢獙鍚庡啀鍒嗘瀽杈撳嚭 +鍙傛暟锛� ts: client绉佹湁鏁版嵁缁撴瀯浣�return锛� 鎵ц缁撴灉鐮侊紝0琛ㄧず姝e父鎵ц +********************************************************/ +static void goodix_ts_work_func(struct work_struct *work) +{ + u8 touch_data[3] = {READ_TOUCH_ADDR_H, READ_TOUCH_ADDR_L, 0}; + u8 key_data[3] ={READ_KEY_ADDR_H, READ_KEY_ADDR_L,0}; + u8 point_data[8*MAX_FINGER_NUM+2]={ 0 }; + static u8 finger_last[MAX_FINGER_NUM+1]={0}; //涓婃瑙︽懜鎸夐敭鐨勬墜鎸囩储寮� + u8 finger_current[MAX_FINGER_NUM+1] = {0}; //褰撳墠瑙︽懜鎸夐敭鐨勬墜鎸囩储寮� + u8 coor_data[6*MAX_FINGER_NUM] = {0}; //瀵瑰簲鎵嬫寚鐨勬暟鎹� + static u8 last_key = 0; + u8 finger = 0; + u8 key = 0; + unsigned int count = 0; + unsigned int position = 0; + int ret=-1; + int tmp = 0; + int temp = 0; + int x = 0, y = 0; + u16 *coor_point; + int syn_flag = 0; + + struct gt818_ts_data *ts = container_of(work, struct gt818_ts_data, work); + + i2c_pre_cmd(ts); + +COORDINATE_POLL: + 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 HAVE_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((touch_data[2] & 0x30) != 0x20) + { + printk("%s:DATA_NO_READY\n", __func__); + goto DATA_NO_READY; + } + + 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 ",); + ts->bad_data = 1; + tmp ++; + ts->retry++; + #ifndef INT_PORT + goto COORDINATE_POLL; + #else + goto XFER_ERROR; + #endif + } + } + //coor_point = (u16 *)coor_data; + + } + + else + { + for(position=1;position < MAX_FINGER_NUM+1; position++) + { + finger_current[position] = 0; + } + } + coor_point = (u16 *)coor_data; + for(position = 1; position < MAX_FINGER_NUM + 1; position++) + { + //printk("%s:positon:%d\n", __func__, 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); + syn_flag =1; + } + else if(finger_current[position]) + { + + x = (*(coor_point+3*(position-1)))*SCREEN_MAX_WIDTH/(TOUCH_MAX_WIDTH); + y = (*(coor_point+3*(position-1)+1))*SCREEN_MAX_HEIGHT/(TOUCH_MAX_HEIGHT); + + if(x < SCREEN_MAX_WIDTH){ + x = SCREEN_MAX_WIDTH-x; + } + + if(y < SCREEN_MAX_HEIGHT){ + // y = SCREEN_MAX_HEIGHT-y; + } + + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 5); + input_mt_sync(ts->input_dev); + syn_flag = 1; + //printk("x:%d ", x); + //printk("y:%d ", y); + //printk("\n"); + } + + } + + if(syn_flag){ + input_sync(ts->input_dev); + } + + for(position = 1; position < MAX_FINGER_NUM + 1; position++) + { + finger_last[position] = finger_current[position]; + } + +#ifdef HAVE_TOUCH_KEY + if((last_key == 0)&&(key == 0)) + goto DATA_NO_READY; + else + { + for(count = 0; count < 4; count++) + { + input_report_key(ts->input_dev, gt818_key_array[count], (key & (0x08 >> count))); + } + } + 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 gt818_ts_data *ts = container_of(timer, struct gt818_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 gt818_ts_data *ts = dev_id; + 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 gt818_ts_data * ts, int on) +{ + int ret = -1; + struct gt818_platform_data *pdata = ts->client->dev.platform_data; + 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); + 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); + return ret; + + case 1: + // #ifdef INT_PORT + // gpio_direction_output(INT_PORT, 0); + // msleep(20); + // gpio_free(INT_PORT); + // s3c_gpio_setpull(INT_PORT, S3C_GPIO_PULL_NONE); + // if(ts->use_irq) + // s3c_gpio_cfgpin(INT_PORT, INT_CFG); //Set IO port as interrupt port + // else + // gpio_direction_input(INT_PORT); + // #else + gpio_direction_output(pdata->gpio_reset, 0); + msleep(1); + gpio_direction_input(pdata->gpio_reset); + // #endif + msleep(40); + ret = 0; + return ret; + + default: + printk(KERN_DEBUG "%s: Cant't support this command.", gt818_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:鍦ㄦ祴璇曞け璐ュ悗闇�閲婃斁ts + int ret = 0; + int retry=0; + u8 goodix_id[3] = {0,0xff,0}; + struct gt818_ts_data *ts; + + struct gt818_platform_data *pdata; + dev_dbg(&client->dev,"Install touch driver.\n"); + printk("gt818: 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 + + pdata = client->dev.platform_data; + + //init int and reset ports +#ifdef INT_PORT + + ret = gpio_request(INT_PORT, "TS_INT"); //Request IO + if (ret){ + dev_err(&client->dev, "Failed to request GPIO:%d, ERRNO:%d\n",(int)INT_PORT, ret); + goto err_gpio_request_failed; + } + rk29_mux_api_set(pdata->pendown_iomux_name, pdata->pendown_iomux_mode); + gpio_direction_input(INT_PORT); + gpio_pull_updown(INT_PORT, 0); + //gpio_set_value(INT_PORT, GPIO_HIGH); +#endif + + ret = gpio_request(pdata->gpio_reset, "gt818_resetPin"); + if(ret){ + dev_err(&client->dev, "failed to request resetPin GPIO%d\n", pdata->gpio_reset); + goto err_gpio_request_failed; + } + rk29_mux_api_set(pdata->resetpin_iomux_name, pdata->resetpin_iomux_mode); + + gpio_direction_output(pdata->gpio_reset, 0); + msleep(1); + gpio_direction_input(pdata->gpio_reset); + gpio_pull_updown(pdata->gpio_reset, 0); + msleep(20); + + + while(0){ + + for(retry = 0; retry < 3; retry++) + { + gpio_direction_output(pdata->gpio_reset, 0); + msleep(1); + gpio_direction_input(pdata->gpio_reset); + gpio_pull_updown(pdata->gpio_reset, 0); + msleep(20); + ret = i2c_write_bytes(client, "hhb", 3); //Test I2C connection. + if (ret > 0) + break; + msleep(500); + } + gpio_direction_output(pdata->gpio_reset, 1); + + } + + if(ret <= 0) + { +// dev_err(&client->dev, "Warnning: I2C communication might be ERROR!\n"); + //goto err_i2c_failed; + } + + INIT_WORK(&ts->work, goodix_ts_work_func); //init work_struct + ts->client = client; + i2c_set_clientdata(client, ts); + + 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) +// ts->input_dev->absbit[0] = BIT(ABS_MT_POSITION_X) | BIT(ABS_MT_POSITION_Y) | +// BIT(ABS_MT_TOUCH_MAJOR) | BIT(ABS_MT_WIDTH_MAJOR); // for android + +#ifdef HAVE_TOUCH_KEY + for(retry = 0; retry < MAX_KEY_NUM; retry++) + { + input_set_capability(ts->input_dev, EV_KEY, gt818_key_array[retry]); + } +#endif + + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); + snprintf(ts->name, sizeof(ts->name), "gt818-touchscreen"); +// sprintf(ts->phys, "input/ts"); + ts->input_dev->name = "gt818_ts";//ts->name; + ts->input_dev->phys = ts->phys; + ts->input_dev->dev.parent = &client->dev; + 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 + +#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, SCREEN_MAX_WIDTH, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, SCREEN_MAX_HEIGHT, 0, 0); +#else + input_set_abs_params(ts->input_dev, ABS_X, 0, SCREEN_MAX_HEIGHT, 0, 0); + input_set_abs_params(ts->input_dev, ABS_Y, 0, SCREEN_MAX_WIDTH, 0, 0); + input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0); +#endif + + + 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 = TS_INT; //If not defined in client + if (client->irq) + { + + #if INT_TRIGGER==0 + #define GT801_PLUS_IRQ_TYPE IRQ_TYPE_EDGE_RISING + #elif INT_TRIGGER==1 + #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(INT_PORT); + gpio_free(INT_PORT); + 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",TS_INT,INT_PORT); + } + } +#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; + } + + +// gpio_direction_output(INT_PORT, 1); +// msleep(1); + + 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 + + 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(INT_PORT); + gpio_free(INT_PORT); + #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 gt818_ts_data *ts = i2c_get_clientdata(client); + struct gt818_platform_data *pdata = client->dev.platform_data; + +#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(INT_PORT); + gpio_free(INT_PORT); + #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 gt818_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 gt818_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 gt818_ts_data *ts; + ts = container_of(h, struct gt818_ts_data, early_suspend); + goodix_ts_suspend(ts->client, PMSG_SUSPEND); +} + +static void goodix_ts_late_resume(struct early_suspend *h) +{ + struct gt818_ts_data *ts; + ts = container_of(h, struct gt818_ts_data, early_suspend); + goodix_ts_resume(ts->client); +} +#endif + + +//鍙敤浜庤椹卞姩鐨�璁惧鍚嶁�璁惧ID 鍒楄〃 +//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; + goodix_wq = create_singlethread_workqueue("goodix_wq"); //create a work queue and worker thread + if (!goodix_wq) { + printk(KERN_ALERT "creat workqueue faiked\n"); + return -ENOMEM; + } + 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"); + i2c_del_driver(&goodix_ts_driver); + if (goodix_wq) + destroy_workqueue(goodix_wq); //release our work queue +} + +late_initcall(goodix_ts_init); //鏈�悗鍒濆鍖栭┍鍔╢elix +module_exit(goodix_ts_exit); + +MODULE_DESCRIPTION("Goodix Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/gt818_ts.h b/drivers/input/touchscreen/gt818_ts.h new file mode 100644 index 000000000000..dbe62519ccf9 --- /dev/null +++ b/drivers/input/touchscreen/gt818_ts.h @@ -0,0 +1,115 @@ +/* + * drivers/input/touchscreen/gt818_ts.h + * + * Copyright (C) 2011 Goodix, Inc. + * + * Author: Felix + * Date: 2011.04.28 + */ + +#ifndef _LINUX_GOODIX_TOUCH_H +#define _LINUX_GOODIX_TOUCH_H + +#include +#include +#include +#include + + +//*************************TouchScreen Work Part***************************** +#define GOODIX_I2C_NAME "gt818_ts" +#define GT801_PLUS +#define GT801_NUVOTON +#define GUITAR_UPDATE_STATE 0x02 +//#define NO_DEFAULT_ID + + +//define resolution of the touchscreen +#define TOUCH_MAX_HEIGHT 7168 +#define TOUCH_MAX_WIDTH 5120 + +//define resolution of the LCD +#define SCREEN_MAX_HEIGHT 800 +#define SCREEN_MAX_WIDTH 480 + + + +#define SHUTDOWN_PORT pdata->gpio_reset //SHUTDOWN¹Ü½ÅºÅ +#define INT_PORT pdata->gpio_pendown + +#ifdef INT_PORT + #define TS_INT gpio_to_irq(INT_PORT) //Interrupt Number +#else + #define TS_INT 0 +#endif + +#define HAVE_TOUCH_KEY + + +#define FLAG_UP 0 +#define FLAG_DOWN 1 +//set GT801 PLUS trigger mode,Ö»ÄÜÉèÖÃ0»ò1 +#define INT_TRIGGER 0 +#define POLL_TIME 10 //actual query spacing interval:POLL_TIME+6 + +#define GOODIX_MULTI_TOUCH +#ifdef GOODIX_MULTI_TOUCH + #define MAX_FINGER_NUM 2 +#else + #define MAX_FINGER_NUM 1 +#endif + +#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0) + +#define READ_TOUCH_ADDR_H 0x07 +#define READ_TOUCH_ADDR_L 0x12 +#define READ_KEY_ADDR_H 0x07 +#define READ_KEY_ADDR_L 0x21 +#define READ_COOR_ADDR_H 0x07 +#define READ_COOR_ADDR_L 0x22 +#define READ_ID_ADDR_H 0x00 +#define READ_ID_ADDR_L 0xff + + +#define IOMUX_NAME_SIZE 48 +struct gt818_platform_data { + + u16 model; /* 818. */ + bool swap_xy; /* swap x and y axes */ + u16 x_min, x_max; + u16 y_min, y_max; + int gpio_reset; + int gpio_reset_active_low; + int gpio_pendown; /* the GPIO used to decide the pendown */ + + char pendown_iomux_name[IOMUX_NAME_SIZE]; + char resetpin_iomux_name[IOMUX_NAME_SIZE]; + int pendown_iomux_mode; + int resetpin_iomux_mode; + + int (*get_pendown_state)(void); +}; + + +struct gt818_ts_data { + + + u16 addr; + u8 bad_data; + struct i2c_client *client; + struct input_dev *input_dev; + int use_reset; //use RESET flag + int use_irq; //use EINT flag + int read_mode; //read moudle mode,20110221 by andrew + struct hrtimer timer; + struct work_struct work; + char phys[32]; + char name[32]; + int retry; + struct early_suspend early_suspend; + int (*power)(struct gt818_ts_data * ts, int on); +}; + + + +#endif /* _LINUX_GOODIX_TOUCH_H */