/* * 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; i < KEY_BUF_SIZE; ++i ) printk("%d,%d\n", keybuffer[i].x, keybuffer[i].y); i = IdxBottom - 1; if ( i <= -1 ) i = KEY_BUF_SIZE - 1; startpoint[0] -= keybuffer[i].x; startpoint[1] -= keybuffer[i].y; //Put your gesture function here!!!! /*if(( startpoint[1]<-50) || (startpoint[1]>50)) 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; i < KEY_BUF_SIZE; ++i ) printk("%d,%d\n", keybuffer[i].x, keybuffer[i].y); i = IdxBottom - 1; if ( i <= -1 ) i = KEY_BUF_SIZE - 1; startpoint[0] -= keybuffer[i].x; startpoint[1] -= keybuffer[i].y; //Put your gesture function here!!!! /*if(( startpoint[1]<-50) || (startpoint[1]>50)) 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; i < KEY_BUF_SIZE; ++i ) printk("%d,%d\n", keybuffer[i].x, keybuffer[i].y); i = IdxBottom - 1; if ( i <= -1 ) i = KEY_BUF_SIZE - 1; startpoint[0] -= keybuffer[i].x; startpoint[1] -= keybuffer[i].y; //Put your gesture function here!!!! /*if(( startpoint[1]<-50) || (startpoint[1]>50)) 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) ) { p_tail = strchr(p_head + 1, 0xd); if ( (p_tail != NULL) && (p_tail < limit) ) { printk("p_head=%lu p_tail=%lu \n", p_head, p_tail); unsigned long length = p_tail - p_head; p_head++; if ( length != 287 ) goto FAIL; char tmpToken[3]; memset(tmpToken, 0, sizeof (tmpToken)); for ( i = 0; i < 143; i++ ) { strncpy(tmpToken, p_head + i * 2, 2); sprintf(cmd_buff + i, "%c", simple_strtol(tmpToken, NULL, 16)); } count++; printk("OpCode[%2x] CRC[%2x][%2x]\n", cmd_buff[0], cmd_buff[141], cmd_buff[142]); opcode = blmode_write_op(cmd_buff); printk("[blmode_write_op][%d]=%d\n", count, opcode); if ( opcode < 0 ) { goto FAIL; } if ( opcode != OPCODE_USER ) { if ( blmode_wait_ready() != 0 ) goto FAIL_BUSY; result = blmode_read_op(opcode); printk("[blmode_read_op]=%d\n", result); if ( result < 0 ) goto FAIL; } data_ptr = p_tail + 1; if ( data_ptr > (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 ]