/* Qisda Tony 090406, add Auo touch i2c driver [ * * 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 //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 //#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_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"); 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"); 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; goto finished; } else{ //printk("goto release \n"); goto release; } } //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,%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"); 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 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); //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; } /*************************/ /*** GPF2 => TP_INT ***/ /*** GPF5 => TOUCH_EN ***/ /*************************/ 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; } break; /*kit.mod 2009/11/04*/ case TOUCH_DEVICE_POWER_STATE: switch(arg) { case TOUCH_DEVICE_ACTIVE_STATE: if(isTouchPowerOff) { isTouchPowerOff = 0; s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT, NULL); 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 = TOUCH_ACTIVE_POLLING_TIME; touchPowerState = TOUCH_DEVICE_ACTIVE_STATE; /*kit.end*/ printk("Touch Device => Active State\n"); break; case TOUCH_DEVICE_SLEEP_STATE: if(isTouchPowerOff) { isTouchPowerOff = 0; s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); 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; s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); 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); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); 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*/ 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"); s3c2410_gpio_pullup(S3C2410_GPF5, 2); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5,1); /*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); s3c2410_gpio_setpin(S3C2410_GPC3,1); #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) { //disable_irq(IRQ_EINT2); /*kit.add 2009/09/24*/ //s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); //s3c2410_gpio_setpin(S3C2410_GPF5, 0); /*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) { if(!isTouchPowerOff) { printk("\nTouch Suspend: Do not add touch to wakeup source, turn off touch power...\n"); disable_irq(IRQ_EINT2); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 0); } } /*kit.end*/ return 0; } static int s3c_ts_iic_resume(struct platform_device *pdev) { /*need to check*/ /*Qisda Qube for open smartcard pwr*/ #if defined (CONFIG_QISDA_AS090B00_EVT1) || defined (CONFIG_QISDA_AS090B00_EVT1_1) /*s3c2410_gpio_pullup(S3C2410_GPF5, 2); s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5,1); msleep(200);*/ s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); s3c2410_gpio_setpin(S3C2410_GPC3, 1); msleep(200); #endif /*Qisda Qube for open smartcard pwr*/ 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) { printk("\nTouch Resume: Touch is not wakeup source, turn on touch power and enable IRQ...\n"); if(!isTouchPowerOff) { s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); s3c2410_gpio_setpin(S3C2410_GPF5, 1); msleep(200); ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL); 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 = TOUCH_ACTIVE_POLLING_TIME; 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; defaule: 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 ]