/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (c) 2009 Tony YC Huang * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "s3c_ts_iic.h" #include //Tony test #include #include /* Qisda, howard hsu, 2010/01/27, TOUCH firmware update { */ #include //for copy_from_user /* } Qisda, howard hsu, 2010/01/27, TOUCH firmware update */ //Aaron, add for the feature of buffered touch data #define USE_BUFFERED_TOUCH_DATA /* Aaron, 20090122, add for CPU sleep prevention */ /* prevent cpu from sleep when any event happens */ #ifdef CONFIG_PM_PLATFORM_POWER_SAVING #define CPU_SLEEP_PREVENT #endif //#ifdef CONFIG_PM_PLATFORM_POWER_SAVING int Cyio_PushEvent(char eventId, char unique); #ifdef USE_BUFFERED_TOUCH_DATA static int go_in_suspend = 0; #endif #ifdef CPU_SLEEP_PREVENT extern unsigned int g_wakeup_event_occurs; #endif //Tony test //#define IN_2416_EMU_BOARD //#define QISDA_TEST_GPIO_PROBE //Qisda Tony 090415 [ //#define POLLING_MODE //#define KTHREAD_USE //Qisda Tony 090415 ] #define DEVICE_NAME "s3c2410-ts-iic" #define TRUE 1 #define FALSE 0 #define printk(x...) //#ifdef IN_2416_EMU_BOARD //#define GPIO_NUM (0x3) //#else //#define GPIO_NUM (0x2) //#endif #define KEY_BUF_SIZE 1 struct s3c_ts_iic { struct input_dev *dev; struct i2c_client *client; struct platform_device *pdev; long xp; long yp; unsigned int polling_time; }; struct t_point { short x; short y; }; static struct platform_driver s3c_ts_iic_driver; static struct work_struct workq_readdata; static struct s3c_ts_iic *ts_iic; static char *s3c_ts_iic_name = "TouchScreen Of IIC Type"; #ifdef QISDA_TEST_GPIO_PROBE static void __iomem *g_pGPIOReg_GPFCON; #endif struct t_point keybuffer[KEY_BUF_SIZE]; static short IdxBottom =0; static struct timer_list touch_iic_timer_qisda; #ifdef POLLING_MODE static int need_calibration = FALSE; #endif #ifdef KTHREAD_USE static wait_queue_head_t wait; static struct task_struct *kmain_task=NULL; #endif //Tony test #define NEW_TCOM_BOARD //static void touch_iic_disable_interrupt(void) { printk("touch_iic_disable_interrupt\n"); writel(readl(S3C24XX_EINTMASK) | (0x1<client->driver->command(ts_iic->client,QISDA_IIC_READ_BUFFERED_POSITION,buffered_data); } //Aaron: send input event. if ((buffered_data[2] == 0) && (buffered_data[3] == 0)) { /* If buffered data is empty, do nothing before return*/ return; } for (i = 1; i < (BUFFERED_DATA_LEN+1); i++) { IndexOffset = 2 * i; /* check if next point data is zero, which means no more data. */ if ((i == BUFFERED_DATA_LEN) || (!buffered_data[IndexOffset + 2] && !buffered_data[IndexOffset + 2 + 1])) { //TODO: send release event. input_report_abs(ts_iic->dev, ABS_X, buffered_data[IndexOffset]); input_report_abs(ts_iic->dev, ABS_Y, buffered_data[IndexOffset + 1]); // //for debug // //printk("\n bufferd_touch_point_handler: panel is touching(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i); if (WithRelease) { if (!IsPanelPressed) { /* in case that only one buffered data with release */ input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); //printk("bufferd_touch_point_handler: panel is Pressed(only one buffered data)\n"); //maybe not necessary//IsPanelPressed = 1; } input_report_key(ts_iic->dev, BTN_TOUCH, 0); input_report_abs(ts_iic->dev, ABS_PRESSURE,0); IsPanelPressed = 0; //printk("bufferd_touch_point_handler: panel is Released(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i); } input_sync(ts_iic->dev); break; } //TODO: send press event input_report_abs(ts_iic->dev, ABS_X, buffered_data[IndexOffset]); input_report_abs(ts_iic->dev, ABS_Y, buffered_data[IndexOffset + 1]); if (!IsPanelPressed) { input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); IsPanelPressed = 1; printk("bufferd_touch_point_handler: panel is Pressed(%d,%d)\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1]); // } else { // //for debug // printk("\n bufferd_touch_point_handler: panel is touching(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i); } input_sync(ts_iic->dev); } } #endif static void ts_iic_workqueue(struct work_struct *work) { static int startpoint[2]; static int emptyKeyBuffer=TRUE; int curpoint[2]; short i=0; #ifdef NEW_TCOM_BOARD static int zeroCount=0; static int prevpoint[2]; #endif //Qisda Tony 090415 [ #ifdef POLLING_MODE #ifdef KTHREAD_USE for(;;){ //This only get the interrupt periodically. No while loop in workqueue, use polling.... //Tony test //Tony test #ifndef NEW_TCOM_BOARD #else ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint); if((curpoint[0]==0) ||(curpoint[1]==0)) { if(emptyKeyBuffer==TRUE) goto finished; #ifdef NEW_TCOM_BOARD else { if(zeroCount<3) { zeroCount++; goto finished; } else { //printk("\nooooo %d,%d\n",curpoint[0],curpoint[1]); goto release; } } #else else goto release; #endif } //key input ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0]; ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1]; input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp); input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp); input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); input_sync(ts_iic->dev); //printk("\n--%d,%d,%d\n",curpoint[0],curpoint[1],IdxBottom); #ifdef NEW_TCOM_BOARD prevpoint[0]=curpoint[0]; prevpoint[1]=curpoint[1]; #endif if(emptyKeyBuffer==TRUE) { emptyKeyBuffer=FALSE; memcpy(startpoint,curpoint,sizeof(startpoint)); printk("\n--%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom); } IdxBottom++; if( IdxBottom >= KEY_BUF_SIZE ) IdxBottom = 0; goto finished; release: printk("++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom); for(i=0;i50)) printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/ // Key input if (Cyio_PushEvent('R', 1) >= 0) { Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 ); } memset(keybuffer,0x0,sizeof(keybuffer)); memset(startpoint,0x0,sizeof(startpoint)); IdxBottom = 0; emptyKeyBuffer = TRUE; //Key input ts_iic->xp =ts_iic->yp = 0; input_report_key(ts_iic->dev, BTN_TOUCH, 0); input_report_abs(ts_iic->dev, ABS_PRESSURE,0); input_sync(ts_iic->dev); #ifdef NEW_TCOM_BOARD prevpoint[0]=0; prevpoint[1]=0; zeroCount = 0; #endif finished: msleep(15); #endif //#if NEW_TCOM_BOARD } #else //Not Ktherad_use //This only get the interrupt periodically. No while loop in workqueue, use polling.... ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint); if((curpoint[0]==0) ||(curpoint[1]==0)) { if(emptyKeyBuffer==TRUE) goto finished; #ifdef NEW_TCOM_BOARD else { if(zeroCount<3) { zeroCount++; goto finished; } else { //printk("\nooooo %d,%d\n", curpoint[0], curpoint[1]); goto release; } } #else else goto release; #endif } //key input ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0]; ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1]; input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp); input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp); input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); input_sync(ts_iic->dev); //printk("\n--%d,%d,%d\n",curpoint[0],curpoint[1],IdxBottom); if(emptyKeyBuffer==TRUE) { emptyKeyBuffer=FALSE; memcpy(startpoint,curpoint,sizeof(startpoint)); printk("\n++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom); } IdxBottom++; if( IdxBottom >= KEY_BUF_SIZE ) IdxBottom = 0; goto finished; release: printk("--%d,%d,%d\n", curpoint[0], curpoint[1],IdxBottom); for(i=0;i50)) printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/ // Key input if (Cyio_PushEvent('R', 1) >= 0) { Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 ); } memset(keybuffer,0x0,sizeof(keybuffer)); memset(startpoint,0x0,sizeof(startpoint)); IdxBottom = 0; emptyKeyBuffer = TRUE; //Key input ts_iic->xp =ts_iic->yp = 0; input_report_key(ts_iic->dev, BTN_TOUCH, 0); input_report_abs(ts_iic->dev, ABS_PRESSURE,0); input_sync(ts_iic->dev); #ifdef NEW_TCOM_BOARD prevpoint[0]=0; prevpoint[1]=0; zeroCount = 0; #endif finished: if(need_calibration){ printk("TOUCH_IIC_CALIBRATION..."); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_CALIBRATION, NULL); need_calibration = FALSE; printk("done\n"); } touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time); mod_timer(&touch_iic_timer_qisda,touch_iic_timer_qisda.expires); return; #endif //KTHREAD_USE #else // NOT POLLING_MODE //This only get the interrupt ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint); if((curpoint[0]==0) ||(curpoint[1]==0)) { //printk("\n[%d] --%d,%d,%d\n", __LINE__, curpoint[0], curpoint[1], emptyKeyBuffer); if(emptyKeyBuffer==TRUE){ emptyKeyBuffer = FALSE; #ifdef USE_BUFFERED_TOUCH_DATA bufferd_touch_point_handler(1); /* with release */ go_in_suspend = 0; #endif goto finished; } else{ //printk("goto release \n"); goto release; } } #ifdef USE_BUFFERED_TOUCH_DATA if (go_in_suspend) { bufferd_touch_point_handler(0); /* without release */ go_in_suspend = 0; } #endif //key input ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0]; ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1]; input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp); input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp); #ifdef USE_BUFFERED_TOUCH_DATA if (!IsPanelPressed) { input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); IsPanelPressed = 1; } #else input_report_key(ts_iic->dev, BTN_TOUCH, 1); input_report_abs(ts_iic->dev, ABS_PRESSURE,1); #endif input_sync(ts_iic->dev); #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPH12, S3C2410_GPH12_OUTP); s3c2410_gpio_setpin(S3C2410_GPH12, 1); #endif //printk("\n[%d] --%d,%d,%d\n", __LINE__, curpoint[0], curpoint[1], emptyKeyBuffer); if((startpoint[0]==0) || (startpoint[1]==0)) { emptyKeyBuffer=FALSE; memcpy(startpoint,curpoint,sizeof(startpoint)); printk("\n++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom); } IdxBottom++; if( IdxBottom >= KEY_BUF_SIZE ) IdxBottom = 0; goto finished; release: printk("--%d,%d,%d\n", curpoint[0], curpoint[1],IdxBottom); for(i=0;i50)) printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/ // Key input if (Cyio_PushEvent('R', 1) >= 0) { Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 ); Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 ); } memset(keybuffer,0x0,sizeof(keybuffer)); memset(startpoint,0x0,sizeof(startpoint)); IdxBottom = 0; emptyKeyBuffer = TRUE; //Key input ts_iic->xp =ts_iic->yp = 0; #ifdef USE_BUFFERED_TOUCH_DATA IsPanelPressed = 0; #endif input_report_key(ts_iic->dev, BTN_TOUCH, 0); input_report_abs(ts_iic->dev, ABS_PRESSURE,0); input_sync(ts_iic->dev); #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPH12, S3C2410_GPH12_OUTP); s3c2410_gpio_setpin(S3C2410_GPH12, 0); #endif #ifdef NEW_TCOM_BOARD prevpoint[0]=0; prevpoint[1]=0; zeroCount = 0; #endif del_timer(&touch_iic_timer_qisda); enable_irq(IRQ_EINT2); //touch_iic_clear_interrupt_pending(); //touch_iic_enable_interrupt(); return; finished: //msleep(15); touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time); mod_timer(&touch_iic_timer_qisda,touch_iic_timer_qisda.expires); return; #endif //Qisda Tony 090415 ] } //static void ts_iic_port_deinit(void) //{ //} //Qisda Tony 090415 [ #ifndef POLLING_MODE static irqreturn_t touch_iic_isr(int irq, void *dev_id) { //static int count=0; printk(KERN_ERR "\ntouch_iic_isr\n"); disable_irq(IRQ_EINT2); #ifdef CPU_SLEEP_PREVENT g_wakeup_event_occurs = 1; //printk("touch_iic_isr: set g_wakeup_event_occurs\n"); #endif //touch_iic_disable_interrupt(); //touch_iic_clear_interrupt_pending(); touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time); add_timer(&touch_iic_timer_qisda); //It wait for kernel timer launch. //schedule_work(&workq_readdata); //Enable interrupt funciton will postphone at workqueue stage //touch_iic_enable_interrupt(); return IRQ_HANDLED; } #endif //Qisda Tony 090415 ] static int s3c_ts_iic_open(struct inode *inode, struct file *file) { return 0; } /* Qisda, howard hsu, 2010/01/27, touch firmware update { */ #define NORMAL_SLAVE_ADDR 0x5C #define BOOTLOADER_SLAVE_ADDR 0x5D #define OPCODE_INIT 0 #define OPCODE_USER 1 #define OPCODE_AES 2 #define OPCODE_EEPROM 3 #define OPCODE_QUERY 8 typedef struct BLModeInfo { char Status; char FlashLock; char Version; char Key; } __attribute__((packed)) BLModeInfo; int normalmode_read_eeprom(unsigned int eepr_addr, unsigned char *buff) { unsigned char tmp[4]; struct i2c_msg msg; unsigned long nmsgs; int ret=0; tmp[0]=120; tmp[1]=0x01;//read tmp[2]=(eepr_addr&0xFF); tmp[3]=eepr_addr>>8; nmsgs=1; msg.len=4; //mem address msg.addr=NORMAL_SLAVE_ADDR; msg.flags=0; msg.buf=tmp; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); nmsgs=1; msg.len=1; //mem address msg.addr=NORMAL_SLAVE_ADDR; msg.flags=I2C_M_RD; msg.buf=buff; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); if(ret<0) printk("normalmode_read_eeprom error code:%d\n",ret); return ret; } int normalmode_read_op(unsigned int mem_addr,unsigned char *buff) { unsigned char tmp[2]; struct i2c_msg msg[2]; unsigned long nmsgs; int ret=0; tmp[0]=mem_addr; //tmp[0]=mem_addr; //tmp[1]=val; nmsgs=2; msg[0].len=1; //mem address msg[0].addr=NORMAL_SLAVE_ADDR; msg[0].flags=0; msg[0].buf=tmp; msg[1].len=1; msg[1].addr=NORMAL_SLAVE_ADDR; msg[1].flags=I2C_M_RD; msg[1].buf=buff; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); if(ret<0) printk("[normalmode_read_op] error:%d\n",ret); else printk("[normalmode_read_op] ok addr:%d value:%d\n",mem_addr,buff[0]); return ret; } int normalmode_write_op(unsigned char mem_addr,unsigned char val) { unsigned char tmp[2]; struct i2c_msg msg; unsigned long nmsgs; int ret=0; tmp[0]=mem_addr; tmp[1]=val; nmsgs=1; msg.len=2; //mem address msg.addr=NORMAL_SLAVE_ADDR; msg.flags=0; msg.buf=tmp; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); if(ret<0) printk("[normalmode_write_op] error:%d\n",ret); else printk("[normalmode_write_op] ok addr:%d value:%d\n",mem_addr,val); return ret; } int blmode_read_op(int opcode) { struct i2c_msg msg; unsigned long nmsgs; int ret=0; BLModeInfo *bl_info = vmalloc(sizeof(BLModeInfo)); nmsgs = 1; msg.addr = BOOTLOADER_SLAVE_ADDR; msg.flags= I2C_M_RD; //0 for write msg.len = 4; msg.buf = bl_info; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); if(ret<0) { printk("[blmode_read_op] error:%d\n",ret); } else { printk("[blmode_read_op] ok:[%x][%x][%x][%x]\n",bl_info->Status,bl_info->FlashLock,bl_info->Version,bl_info->Key); if ( (bl_info->Status&0x80) != 0) { ret = -8; } else { if (opcode==OPCODE_AES) { if(bl_info->FlashLock==0x00) printk("=Flash is locked\n"); else if (bl_info->FlashLock==0x05) printk("=Flash verified failed\n"); else if (bl_info->FlashLock==0xFF) printk("=Flash is erased\n"); else if (bl_info->FlashLock==0xA5) printk("=Flash is unlocked\n"); else printk("=Flash status Unknown(%x)\n",bl_info->FlashLock); } } } return ret; } int blmode_write_op(char *data_ptr) { struct i2c_msg msg; unsigned long nmsgs; int ret=0; nmsgs = 1; msg.addr = BOOTLOADER_SLAVE_ADDR; msg.flags= 0; msg.len = 143; msg.buf = data_ptr; ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs); if(ret<0) { printk("blmode_write_op error:%d\n",ret); } else { ret = data_ptr[0]; printk("opcode[%d] OK\n",data_ptr[0]); } return ret; } int blmode_wait_ready() { unsigned int pin_state; int count = 0; int ret =0; do { pin_state = (__raw_readl(S3C2410_GPFDAT)&(1<<2)); count++; msleep(20); } while((pin_state!=0)&&(count<100)); //wait for 2 seconds //printk("[blmode_wait_ready]count=%d pin=%d\n",count,pin_state); ret = (pin_state==0)? 0:1; return ret; } int get_touch_firmware_info(char *buff) { /* read version */ normalmode_read_op(119,buff); } int enter_blmode (int method) { disable_irq(IRQ_EINT2); s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); s3c2410_gpio_pullup(S3C2410_GPF2, 0); if( method==0 ) { printk("TP:HW_blmode entry\n"); //turn-off #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 0); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); #endif msleep(2000); #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif //s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); //s3c2410_gpio_pullup(S3C2410_GPF2, 0); blmode_read_op(OPCODE_QUERY); blmode_wait_ready(); blmode_read_op(OPCODE_QUERY); } else { printk("TP:SW_blmode entry\n"); msleep(100); normalmode_write_op(120,5); blmode_read_op(OPCODE_QUERY); blmode_wait_ready(); blmode_read_op(OPCODE_QUERY); } } int reset_touch() { #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 0); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); #endif //s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); //?smart card //s3c2410_gpio_setpin(S3C2410_GPC3, 0); msleep(2000); //on //s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); //s3c2410_gpio_pullup(S3C2410_GPF2, 2); #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif msleep(400); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); enable_irq(IRQ_EINT2); msleep(100); } int update_touch_firmware(unsigned long size, char* frame_data) { unsigned int pin_state; int count, count_max; int opcode, result; int i; unsigned long offset = 0; /* disable_irq(IRQ_EINT2); s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); s3c2410_gpio_pullup(S3C2410_GPF2, 0); msleep(100); normalmode_write_op(120,5); blmode_wait_ready(); blmode_read_op(OPCODE_QUERY); */ enter_blmode(0); char *cmd_buff = vmalloc(143, GFP_KERNEL); char *data_ptr = frame_data; unsigned long limit = frame_data + size; char *p_head; char *p_tail; count = 0; do { p_head = strchr(data_ptr,'$'); if ( (p_head != NULL)&& (p_tail (limit-280) ) { printk("end of file,stop\n"); printk("curr:%lu limit:%lu\n",data_ptr,limit); p_head=0; } } else { p_head=0; } } printk("==p_head=%lu\n",p_head); } while(p_head!=0); vfree(cmd_buff); /* printk("restore EINT\n"); s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); enable_irq(IRQ_EINT2); msleep(100); */ reset_touch(); return 0; FAIL_BUSY: printk("[FAIL]Dev is Busy\n"); FAIL: return -1; } /* } Qisda, howard hsu, 2010/01/27, touch firmware update */ /*******************************/ /****** GPF2 => TP_INT ******/ /****** GPF5 => TOUCH_EN ******/ /*** GPC3 => T-Sensor Power ***/ /*******************************/ static int s3c_ts_iic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd){ case TOUCH_IIC_CALIBRATION: #ifdef POLLING_MODE need_calibration = TRUE; #else printk("TOUCH_IIC_CALIBRATION..."); disable_irq(IRQ_EINT2); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_CALIBRATION, NULL); printk("done\n"); enable_irq(IRQ_EINT2); #endif break; case TOUCH_IIC_SET_POLLING_TIME: if((arg<1) || (arg>80)){ printk("polling time should be 1-80\n"); } else{ ts_iic->polling_time = arg; touchPollingTime = arg; } break; /*kit.mod 2009/11/04*/ case TOUCH_DEVICE_POWER_STATE: switch(arg) { case TOUCH_DEVICE_ACTIVE_STATE: if(isTouchPowerOff) { isTouchPowerOff = 0; #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT, NULL); /*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); /*kit.end*/ enable_irq(IRQ_EINT2); } ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_ACTIVE_MODE, NULL); /*kit.add 2009/11/16*/ ts_iic->polling_time = touchPollingTime; touchPowerState = TOUCH_DEVICE_ACTIVE_STATE; /*kit.end*/ printk("Touch Device => Active State\n"); break; case TOUCH_DEVICE_SLEEP_STATE: if(isTouchPowerOff) { isTouchPowerOff = 0; #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); /*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); /*kit.end*/ enable_irq(IRQ_EINT2); } ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_SLEEP_MODE, NULL); /*kit.add 2009/11/16*/ ts_iic->polling_time = TOUCH_SLEEP_POLLING_TIME; touchPowerState = TOUCH_DEVICE_SLEEP_STATE; /*kit.end*/ printk("Touch Device => Sleep State\n"); break; case TOUCH_DEVICE_DEEPSLEEP_STATE: if(isTouchPowerOff) { isTouchPowerOff = 0; #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); /*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); /*kit.end*/ enable_irq(IRQ_EINT2); } ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_DEEPSLEEP_MODE, NULL); /*kit.add 2009/11/16*/ ts_iic->polling_time = TOUCH_DEEPSLEEP_POLLING_TIME; touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE; /*kit.end*/ printk("Touch Device => Deep Sleep State\n"); break; case TOUCH_DEVICE_POWEROFF_STATE: if(isTouchPowerOff) printk("Touch Device => Already Power Off State\n"); else { isTouchPowerOff = 1; disable_irq(IRQ_EINT2); /*kit.add 2010/01/20, turn off TP_INT(GPF2) power*/ /*test1: TP_INT(GPF2) => Input, Disable*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); s3c2410_gpio_pullup(S3C2410_GPF2, 0); /*test2: TP_INT(GPF2) => Input, Pull Low*/ //s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); //s3c2410_gpio_setpin(S3C2410_GPF2, 1); /*kit.end*/ /*Turn off touch power(TOUCH_EN)*/ #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 0); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); #endif printk("Touch Device => Power Off State\n"); } /*kit.add 2009/11/16*/ touchPowerState = TOUCH_DEVICE_POWEROFF_STATE; /*kit.end*/ break; default: printk("Touch Device => No Such Power State...\n"); } break; /*kit.end*/ /* Qisda, howard hsu, 2010/01/27, TOUCH firmware update { */ case TOUCH_IIC_FW_UPDATE: { printk("Call TOUCH_IIC_FW_UPDATE\n"); unsigned long fw_size = 0; int result = 0; if(copy_from_user(&fw_size, (unsigned long*) arg, sizeof(unsigned long))) return -EFAULT; unsigned char *fw_data = vmalloc(fw_size, GFP_KERNEL); if(copy_from_user(fw_data, (char*) ((char *)arg+sizeof(unsigned long)), fw_size)) return -EFAULT; printk("FW_Size=%d\n",fw_size); result = update_touch_firmware(fw_size,fw_data); printk("TOUCH_IIC_FW_UPDATE Complete(result=%d)!!!\n",result); vfree(fw_data); return result; } break; case TOUCH_IIC_GET_FW_INFO: { char info = 0; get_touch_firmware_info(&info); if(copy_to_user((void *)arg, (const void *) &info, sizeof(char))) return -EFAULT; } break; /* } Qisda, howard hsu, 2010/01/27, TOUCH firmware update */ /*kit.add 2010/01/30*/ case TOUCH_IIC_T_SENSOR_ENABLE: { switch(arg) { case 0: s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); s3c2410_gpio_setpin(S3C2410_GPC3, 0); printk("T-Sensor power off\n"); break; case 1: s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); s3c2410_gpio_setpin(S3C2410_GPC3, 1); printk("T-Sensor power on\n"); break; default: printk("T-Sensor no such command\n"); break; } } break; /*kit.end*/ default: printk("No such command\n"); } return 0; } /* File operations struct for character device */ static const struct file_operations s3c_ts_iic_fops = { .owner = THIS_MODULE, .ioctl = s3c_ts_iic_ioctl, .open = s3c_ts_iic_open, .release = NULL }; int s3c_ts_iic_port_init(struct i2c_client *c) { int err = 0; ts_iic->client = c; err = c->driver->command(c,QISDA_IIC_INIT,NULL); if(err<0){ printk("Touch init faied\n"); goto fail; } //touch_iic_init(); //touch_iic_port_initialize(); //Qisda Tony 090415 [ #ifdef POLLING_MODE #ifdef KTHREAD_USE init_waitqueue_head(&wait); kmain_task = kthread_create(ts_iic_workqueue, NULL,"ts_iic_kthread"); wake_up_process(kmain_task); #else init_timer(&touch_iic_timer_qisda); touch_iic_timer_qisda.function =touhc_iic_timer_handler_qisda; //touch_iic_timer_qisda.data; touch_iic_timer_qisda.expires = jiffies + 10*HZ; add_timer(&touch_iic_timer_qisda); #endif #else //NOT POLLING_MODE s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); s3c2410_gpio_pullup(S3C2410_GPF2, 2); #ifndef KTHREAD_USE init_timer(&touch_iic_timer_qisda); touch_iic_timer_qisda.function =touhc_iic_timer_handler_qisda; #endif set_irq_type(IRQ_EINT2, S3C2410_EXTINT_FALLEDGE); err = request_irq(IRQ_EINT2, touch_iic_isr, SA_INTERRUPT, DEVICE_NAME, (void *) ts_iic->pdev); if (err) { printk("request_irq failed (IRQ_EINT2) !!!\n"); free_irq(IRQ_EINT2, ts_iic->dev); //ts_iic_port_deinit(); goto fail; } //touch_iic_clear_interrupt_pending(); //touch_iic_enable_interrupt(); #endif //End of NOT POLLING_MODE memset(keybuffer,0x0,sizeof(keybuffer)); //Qisda Tony 090415 ] if (register_chrdev (TOUCH_MAJOR, "touch_cmd", &s3c_ts_iic_fops)) { printk("unable to get major %d\n", TOUCH_MAJOR); } printk("s3c_ts_iic_port_init is initialized!!\n"); #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_pullup(S3C2410_GPD10, 2); s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10,1); #else s3c2410_gpio_pullup(S3C2410_GPF5, 2); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5,1); #endif /*Qisda Qube for open smartcard pwr*/ #if defined (CONFIG_QISDA_AS090B00_EVT1) || defined (CONFIG_QISDA_AS090B00_EVT1_1) s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); /*kit.mod 2009/12/25*/ s3c2410_gpio_setpin(S3C2410_GPC3, 0); /*kit.end*/ #endif /*Qisda Qube for open smartcard pwr*/ return 0; fail: platform_driver_unregister(&s3c_ts_iic_driver); input_free_device(ts_iic->dev); kfree(ts_iic); return -EIO; } static int __init s3c_ts_iic_probe(struct platform_device *pdev) { struct input_dev *input_dev; int err; //Tony test #ifdef QISDA_TEST_GPIO_PROBE g_pGPIOReg_GPFCON = ioremap(0x56000050, 0x00100000); writel(readl(g_pGPIOReg_GPFCON) | (0x1<<0), g_pGPIOReg_GPFCON); writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04); writel(readl(g_pGPIOReg_GPFCON+0x08) | (0x2<<0), g_pGPIOReg_GPFCON+0x08); #endif ts_iic = kzalloc(sizeof(struct s3c_ts_iic), GFP_KERNEL); input_dev = input_allocate_device(); if (!input_dev) { err = -ENOMEM; goto fail; } ts_iic->dev = input_dev; ts_iic->dev->evbit[0] = ts_iic->dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); ts_iic->dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(ts_iic->dev, ABS_X, 0, 0xFFF, 0, 0); input_set_abs_params(ts_iic->dev, ABS_Y, 0, 0xFFF, 0, 0); input_set_abs_params(ts_iic->dev, ABS_PRESSURE, 0, 1, 0, 0); ts_iic->dev->private = ts_iic; ts_iic->dev->name = s3c_ts_iic_name; ts_iic->dev->id.bustype = BUS_I2C; ts_iic->dev->id.vendor = 0xDEAD; ts_iic->dev->id.product = 0xBEEF; ts_iic->dev->id.version = 0x0010; platform_set_drvdata(pdev, ts_iic); /* All went ok, so register to the input system */ err = input_register_device(ts_iic->dev); if(err) { goto fail; } ts_iic->pdev = pdev; ts_iic->polling_time = 20; INIT_WORK(&workq_readdata,ts_iic_workqueue); //However, stop interrupt first. This is because the signal is emitted from the panel repeatedly //Unless we set the interrupt mode of the the panel to stop emitting. //touch_iic_disable_interrupt(); //printk("s3c_ts_iic_probe IRQ is initialized!!\n"); // touch panel enable in common-smdk.c //writel((readl(S3C2416_GPKCON) & ~(1<<5) | (1<<4)), S3C2416_GPKCON); //writel((readl(S3C2416_GPKDAT) | (1<<2)), S3C2416_GPKDAT); return 0; fail: input_free_device(input_dev); kfree(ts_iic); return -EIO; } static int s3c_ts_iic_remove(struct platform_device *dev) { return 0; } #ifdef CONFIG_PM static int s3c_ts_iic_suspend(struct platform_device *dev, pm_message_t state) { /*kit.add 2010/01/06, turn off Tilt-Sensor power*/ s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); s3c2410_gpio_setpin(S3C2410_GPC3, 0); /*kit.end*/ /*kit.test 2010/01/30, turn off SPI_INT power*/ s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_INP); s3c2410_gpio_pullup(S3C2410_GPF3, 0); /* pull-up/down disable */ /*kit.end*/ /*kit.add 2009/11/04*/ if(wkup_srce == 1) { printk("\nTouch Suspend: Add touch to wakeup source, do not turn off touch power...\n"); } //else if(wkup_srce == 0) else { if(!isTouchPowerOff) { printk("\nTouch Suspend: Do not add touch to wakeup source, turn off touch power...\n"); disable_irq(IRQ_EINT2); /*kit.add 2010/01/20, turn off TP_INT(GPF2) power*/ /*test1: TP_INT(GPF2) => Input, Disable*/ //s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); //s3c2410_gpio_pullup(S3C2410_GPF2, 0); /*test2: TP_INT(GPF2) => Input, Pull Low*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); s3c2410_gpio_setpin(S3C2410_GPF2, 1); /*kit.end*/ /*turn off TOUCH_EN power*/ #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 0); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); #endif } } /*kit.end*/ #ifdef USE_BUFFERED_TOUCH_DATA go_in_suspend = 1; #endif return 0; } static int s3c_ts_iic_resume(struct platform_device *pdev) { /*kit.add 2010/01/06, for Tilt-Sensor power*/ s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); s3c2410_gpio_setpin(S3C2410_GPC3, 1); /*kit.end*/ /*kit.test 2010/01/30, for SPI_INT power*/ s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_EINT3); s3c2410_gpio_pullup(S3C2410_GPF3, 2); /* pull-up enable */ /*kit.end*/ ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT, NULL); /*kit.add 2009/11/04*/ if(wkup_srce == 1) { printk("\nTouch Resume: Touch is wakeup source\n"); } //else if(wkup_srce == 0) else { printk("\nTouch Resume: Touch is not wakeup source, turn on touch power and enable IRQ...\n"); if(!isTouchPowerOff) { /*turn on TOUCH_EN power*/ #ifdef CONFIG_QISDA_BK060B00 s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP); s3c2410_gpio_setpin(S3C2410_GPD10, 1); #else s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); #endif msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); /*kit.add 2010/01/20, config TP_INT(GPF2) to interrupt*/ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2); s3c2410_gpio_pullup(S3C2410_GPF2, 2); /*kit.end*/ enable_irq(IRQ_EINT2); switch(touchPowerState) { case TOUCH_DEVICE_ACTIVE_STATE: ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_ACTIVE_MODE, NULL); ts_iic->polling_time = touchPollingTime; touchPowerState = TOUCH_DEVICE_ACTIVE_STATE; break; case TOUCH_DEVICE_SLEEP_STATE: ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_SLEEP_MODE, NULL); ts_iic->polling_time = TOUCH_SLEEP_POLLING_TIME; touchPowerState = TOUCH_DEVICE_SLEEP_STATE; break; case TOUCH_DEVICE_DEEPSLEEP_STATE: ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_DEEPSLEEP_MODE, NULL); ts_iic->polling_time = TOUCH_DEEPSLEEP_POLLING_TIME; touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE; break; case TOUCH_DEVICE_POWEROFF_STATE: touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE; break; default: break; } } } /*kit.end*/ return 0; } #else #define s3c_ts_iic_suspend NULL #define s3c_ts_iic_resume NULL #endif static struct platform_driver s3c_ts_iic_driver = { .probe = s3c_ts_iic_probe, .remove = s3c_ts_iic_remove, .suspend = s3c_ts_iic_suspend, .resume = s3c_ts_iic_resume, .driver = { .owner = THIS_MODULE, .name = DEVICE_NAME, }, }; //static char banner[] __initdata = KERN_INFO "Touchscreen driver Of IIC type for Qisda\n"; static int __init s3c_ts_iic_init(void) { return platform_driver_register(&s3c_ts_iic_driver); } static void __exit s3c_ts_iic_exit(void){ platform_driver_unregister(&s3c_ts_iic_driver); } module_init(s3c_ts_iic_init); module_exit(s3c_ts_iic_exit); MODULE_AUTHOR("Tony.YC.Huang@qisda.com"); MODULE_DESCRIPTION("Touchscreen driver Of IIC type for Qisda"); MODULE_LICENSE("GPL"); //Qisda Tony 090406, add Auo touch i2c driver ]