add touchscreen support for a22
authorluowei <lw@rock-chips.com>
Thu, 24 Mar 2011 09:44:03 +0000 (17:44 +0800)
committerluowei <lw@rock-chips.com>
Thu, 24 Mar 2011 09:44:03 +0000 (17:44 +0800)
arch/arm/mach-rk29/board-rk29-a22.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ili2102_ts.c [new file with mode: 0755]
drivers/input/touchscreen/ili2102_ts.h [new file with mode: 0755]

index 3d93121e3782ff587f298fa8c0e267d7816f8913..7b3f9e55787b8ada50d13b3b066eb464d3a3b995 100755 (executable)
@@ -1231,6 +1231,29 @@ struct platform_device rk29_device_gps = {
        };
 #endif
 
+
+#if defined(CONFIG_TOUCHSCREEN_ILI2102_IIC) 
+#include "../../../drivers/input/touchscreen/ili2102_ts.h"
+#define GT801_GPIO_INT      RK29_PIN4_PD5
+#define GT801_GPIO_RESET    RK29_PIN6_PC3
+static struct ili2102_platform_data ili2102_info = {
+       .model                  = 2102,
+       .swap_xy                = 0,
+       .x_min                  = 0,
+       .x_max                  = 480,
+       .y_min                  = 0,
+       .y_max                  = 800,
+       .gpio_reset     = GT801_GPIO_RESET,
+       .gpio_reset_active_low = 1,
+       .gpio_pendown           = GT801_GPIO_INT,
+       .pendown_iomux_name = GPIO4D5_CPUTRACECTL_NAME,
+       .resetpin_iomux_name = NULL,
+       .pendown_iomux_mode = GPIO4H_GPIO4D5,
+       .resetpin_iomux_mode = 0,
+};
+#endif
+
+
 /*****************************************************************************************
  * i2c devices
  * author: kfx@rock-chips.com
@@ -1409,6 +1432,15 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
 
 #ifdef CONFIG_I2C2_RK29
 static struct i2c_board_info __initdata board_i2c2_devices[] = {
+#if defined (CONFIG_TOUCHSCREEN_ILI2102_IIC)
+{
+       .type           = "ili2102_ts",
+       .addr           = 0x41,
+       .flags          = 0,
+       .irq            = RK29_PIN4_PD5,
+       .platform_data = &ili2102_info,
+},     
+#endif
 #if defined (CONFIG_MFD_WM831X_I2C)
 {
        .type           = "wm8310",
index 8bb1b247b4ad08b2a42d62424de8884bb90c9785..90678fb41d6a91c387a2c1da9996e26a3ea7b911 100755 (executable)
@@ -13,7 +13,7 @@ if INPUT_TOUCHSCREEN
 
 config TOUCHSCREEN_XPT2046_SPI
        tristate "XPT2046 based touchscreens:SPI Interface"
-       depends on SPIM_RK2818 || SPIM_RK29
+       depends on SPIM_RK29
        
        config TOUCHSCREEN_XPT2046_NORMAL_SPI
        tristate "normal mode"
@@ -63,6 +63,31 @@ config TOUCHSCREEN_XPT2046_SPI
                tristate "320X480 resolution"
                depends on TOUCHSCREEN_XPT2046_CBN_SPI
 
+#choice 
+#  prompt "XPT2046 based touchscreens: SPI Interface"
+#  default TOUCHSCREEN_XPT2046_CBN_SPI
+         
+#  config TOUCHSCREEN_XPT2046_SPI_NOCHOOSE
+#    bool "DO NOT CHOOSE TOUCHSCREEN_XPT2046"
+  
+#  config TOUCHSCREEN_XPT2046_SPI
+#    bool "800X480 TOUCHSCREEN"
+#   depends on SPIM_RK2818 || SPIM_RK29
+
+#  config TOUCHSCREEN_XPT2046_CBN_SPI
+#    bool "800X480 CALIBRATION TOUCHSCREEN"
+#    depends on SPIM_RK2818 || SPIM_RK29
+  
+#  config TOUCHSCREEN_XPT2046_320X480_SPI
+#    bool "320X480 TOUCHSCREEN"
+#    depends on SPIM_RK2818 || SPIM_RK29
+  
+#  config TOUCHSCREEN_XPT2046_320X480_CBN_SPI
+#      bool "320X480 CALIBRATION TOUCHSCREEN"
+#      depends on SPIM_RK2818 || SPIM_RK29     
+#endchoice
+
+
 config TOUCHSCREEN_ADS7846
        tristate "ADS7846/TSC2046 and ADS7843 based touchscreens"
        depends on SPI_MASTER
@@ -94,6 +119,15 @@ config TOUCHSCREEN_AD7877
          To compile this driver as a module, choose M here: the
          module will be called ad7877.
          
+config TOUCHSCREEN_ILI2102_IIC
+       tristate "ili2102 based touchscreens: IIC Interface"
+       help
+         Say Y here if you have a touchscreen interface using the
+         hx8520 controller, and your board-specific initialization
+         code includes that in its table of IIC devices.
+
+         If unsure, say N (but it's safe to say "Y").
+
 config RK28_I2C_TS_NTP070
        tristate "NTP070 based touchscreens: NTP070 Interface"
        depends on I2C_RK2818
@@ -718,5 +752,4 @@ config TOUCHSCREEN_IT7260
 config TOUCHSCREEN_GT801_IIC
        tristate "GT801_IIC based touchscreens"
        depends on I2C2_RK29
-
 endif
index 1681c0ead5b3aa7c7fca729594aa7b3b80dfa770..93da2e595244afd295fa317d7b53c83cc4aebfb2 100644 (file)
@@ -54,4 +54,5 @@ obj-$(CONFIG_SINTEK_3FA16)    +=  sintek_3FA16.o
 obj-$(CONFIG_EETI_EGALAX)              += eeti_egalax_i2c.o
 obj-$(CONFIG_ATMEL_MXT224)               += atmel_mxt224.o
 obj-$(CONFIG_TOUCHSCREEN_GT801_IIC)      += gt801_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ILI2102_IIC)      += ili2102_ts.o
 
diff --git a/drivers/input/touchscreen/ili2102_ts.c b/drivers/input/touchscreen/ili2102_ts.c
new file mode 100755 (executable)
index 0000000..b932717
--- /dev/null
@@ -0,0 +1,596 @@
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <mach/iomux.h>
+#include <linux/platform_device.h>
+
+#include "ili2102_ts.h"
+
+
+#if 1
+       #define DBG(msg...)     printk(msg);
+#else
+       #define DBG(msg...)
+#endif
+
+#define TOUCH_NUMBER 2
+
+static int touch_state[TOUCH_NUMBER] = {TOUCH_UP,TOUCH_UP};
+static struct workqueue_struct *ili2102_wq;
+
+struct ili2102_ts_data {
+       u16             model;                  /* 801. */      
+       bool    swap_xy;                /* swap x and y axes */ 
+       u16             x_min, x_max;   
+       u16             y_min, y_max;
+    uint16_t addr;
+    int        use_irq;
+       int     gpio_pendown;
+       int     gpio_reset;
+       int     gpio_reset_active_low;
+       int             pendown_iomux_mode;     
+       int             resetpin_iomux_mode;
+       char    pendown_iomux_name[IOMUX_NAME_SIZE];    
+       char    resetpin_iomux_name[IOMUX_NAME_SIZE];   
+       char    phys[32];
+       char    name[32];
+    struct     i2c_client *client;
+    struct     input_dev *input_dev;
+    struct     hrtimer timer;
+    struct     work_struct  work;
+    struct     early_suspend early_suspend;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void ili2102_ts_early_suspend(struct early_suspend *h);
+static void ili2102_ts_late_resume(struct early_suspend *h);
+#endif
+
+static int verify_coord(struct ili2102_ts_data *ts,unsigned int *x,unsigned int *y)
+{
+
+       DBG("%s:(%d/%d)\n",__FUNCTION__,*x, *y);
+       if((*x< ts->x_min) || (*x > ts->x_max))
+               return -1;
+
+       if((*y< ts->y_min) || (*y > ts->y_max))
+               return -1;
+
+       return 0;
+}
+static int ili2102_init_panel(struct ili2102_ts_data *ts)
+{
+    return 0;
+}
+static void ili2102_test(struct i2c_client *client)
+{
+       int i;
+    int ret;
+       struct i2c_msg msg[2];
+    uint8_t start_reg;
+    uint8_t buf[4];
+
+       start_reg = 0x31;
+
+    msg[0].addr =client->addr;
+    msg[0].flags = 0;
+    msg[0].len = 1;
+    msg[0].buf = &start_reg;
+    
+    msg[1].addr = client->addr;
+    msg[1].flags = I2C_M_RD;
+    msg[1].len = 3;
+    msg[1].buf = buf;
+
+       
+       ret = i2c_transfer(client->adapter, msg, 2);
+    
+    if (ret < 0) {
+         printk("ili2102_test:i2c_transfer fail =%d\n",ret);
+    }
+
+    for(i=0; i<3; i++){
+        printk("ili2102_test:buf[%d]=%x\n", i, buf[i]);
+    }
+       
+
+       
+}
+static void ili2102_ts_work_func(struct work_struct *work)
+{
+    int i,ret;
+    int syn_flag = 0;
+    unsigned int x, y;
+    struct i2c_msg msg[2];
+    uint8_t start_reg;
+    uint32_t buf[4];
+    struct ili2102_ts_data *ts = container_of(work, struct ili2102_ts_data, work);
+       
+       DBG("ili2102_ts_work_func\n");
+               
+    start_reg = 0x86;
+
+    msg[0].addr = ts->client->addr;
+    msg[0].flags = 0;
+    msg[0].len = 1;
+    msg[0].buf = &start_reg;
+    
+    msg[1].addr = ts->client->addr;
+    msg[1].flags = I2C_M_RD;
+    msg[1].len = 4 * TOUCH_NUMBER;
+    msg[1].buf = (u8*)&buf[0];
+
+    ret = i2c_transfer(ts->client->adapter, msg, 2);
+    
+    if (ret < 0) {
+      for(i=0; i<TOUCH_NUMBER; i++) buf[i] = 0xffffffff;
+         printk("ili2102_ts_work_func:i2c_transfer fail =%d\n",ret);
+    }
+
+    for(i=0; i<TOUCH_NUMBER; i++){
+      if(buf[i] == 0xffffffff || buf[i] == 0){
+               if (touch_state[i] == TOUCH_DOWN)
+               {
+                       DBG("ili2102_ts_work_func:buf[%d]=%d\n",i,buf[i]);
+               input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); //Finger Size
+               input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); //Touch Size
+               input_mt_sync(ts->input_dev);
+                       syn_flag = 1;
+                       touch_state[i] = TOUCH_UP;
+               }
+               
+      }
+      else{
+        x = ((buf[i] & 0xff) << 8) | ((buf[i] & 0xff00) >> 8);
+        y = ((buf[i] & 0xff0000) >> 8) | ((buf[i] & 0xff000000) >> 24);
+
+               if (ts->swap_xy)
+                       swap(x, y);
+               
+               if (verify_coord(ts,&x,&y))
+                       goto out;
+               
+        DBG("buf[%d]=%x X = %d, Y = %d\n", i, buf[i], x, y);
+
+        input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); //Finger Size
+        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); //Touch Size
+        input_mt_sync(ts->input_dev);
+               syn_flag = 1;
+               touch_state[i] = TOUCH_DOWN;
+      }
+    }
+       
+       if(syn_flag)
+               input_sync(ts->input_dev);
+out:   
+       
+    if (ts->use_irq) 
+               enable_irq(ts->client->irq);
+       
+    return;
+}
+
+static enum hrtimer_restart ili2102_ts_timer_func(struct hrtimer *timer)
+{
+    struct ili2102_ts_data *ts = container_of(timer, struct ili2102_ts_data, timer);
+    DBG("ili2102_ts_timer_func\n"); 
+
+    queue_work(ili2102_wq, &ts->work);
+
+    hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+    return HRTIMER_NORESTART;
+}
+
+static irqreturn_t ili2102_ts_irq_handler(int irq, void *dev_id)
+{
+    struct ili2102_ts_data *ts = dev_id;
+       DBG("ili2102_ts_irq_handler=%d,%d\n",ts->client->irq,ts->use_irq);
+       
+       //if (ts->use_irq)
+       disable_irq_nosync(ts->client->irq); //disable_irq(ts->client->irq);
+    queue_work(ili2102_wq, &ts->work);
+    return IRQ_HANDLED;
+}
+
+static int __devinit setup_resetPin(struct i2c_client *client, struct ili2102_ts_data *ts)
+{
+       struct ili2102_platform_data    *pdata = client->dev.platform_data;
+       int err;
+       
+       ts->gpio_reset = pdata->gpio_reset;
+       strcpy(ts->resetpin_iomux_name,pdata->resetpin_iomux_name);
+       ts->resetpin_iomux_mode = pdata->resetpin_iomux_mode;
+       ts->gpio_reset_active_low = pdata->gpio_reset_active_low;
+       
+       DBG("%s=%d,%s,%d,%d\n",__FUNCTION__,ts->gpio_reset,ts->resetpin_iomux_name,ts->resetpin_iomux_mode,ts->gpio_reset_active_low);
+
+       if (!gpio_is_valid(ts->gpio_reset)) {
+               dev_err(&client->dev, "no gpio_reset?\n");
+               return -EINVAL;
+       }
+
+    rk29_mux_api_set(ts->resetpin_iomux_name,ts->resetpin_iomux_mode); 
+       err = gpio_request(ts->gpio_reset, "ili2102_resetPin");
+       if (err) {
+               dev_err(&client->dev, "failed to request resetPin GPIO%d\n",
+                               ts->gpio_reset);
+               return err;
+       }
+       
+       gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_LOW:GPIO_HIGH);
+
+       err = gpio_direction_output(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_LOW:GPIO_HIGH);
+       if (err) {
+               dev_err(&client->dev, "failed to pulldown resetPin GPIO%d\n",
+                               ts->gpio_reset);
+               gpio_free(ts->gpio_reset);
+               return err;
+       }
+       
+    mdelay(100);
+
+       gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
+
+       mdelay(100);
+        
+       return 0;
+}
+
+static int __devinit setup_pendown(struct i2c_client *client, struct ili2102_ts_data *ts)
+{
+       int err;
+       struct ili2102_platform_data    *pdata = client->dev.platform_data;
+       
+       if (!client->irq) {
+               dev_dbg(&client->dev, "no IRQ?\n");
+               return -ENODEV;
+       }
+       
+       if (!gpio_is_valid(pdata->gpio_pendown)) {
+               dev_err(&client->dev, "no gpio_pendown?\n");
+               return -EINVAL;
+       }
+       
+       ts->gpio_pendown = pdata->gpio_pendown;
+       strcpy(ts->pendown_iomux_name,pdata->pendown_iomux_name);
+       ts->pendown_iomux_mode = pdata->pendown_iomux_mode;
+       
+       DBG("%s=%d,%s,%d\n",__FUNCTION__,ts->gpio_pendown,ts->pendown_iomux_name,ts->pendown_iomux_mode);
+       
+       if (!gpio_is_valid(ts->gpio_pendown)) {
+               dev_err(&client->dev, "no gpio_pendown?\n");
+               return -EINVAL;
+       }
+       
+    rk29_mux_api_set(ts->pendown_iomux_name,ts->pendown_iomux_mode);
+       err = gpio_request(ts->gpio_pendown, "ili2102_pendown");
+       if (err) {
+               dev_err(&client->dev, "failed to request pendown GPIO%d\n",
+                               ts->gpio_pendown);
+               return err;
+       }
+       
+       err = gpio_pull_updown(ts->gpio_pendown, GPIOPullUp);
+       if (err) {
+               dev_err(&client->dev, "failed to pullup pendown GPIO%d\n",
+                               ts->gpio_pendown);
+               gpio_free(ts->gpio_pendown);
+               return err;
+       }
+       return 0;
+}
+static int ili2102_chip_Init(struct i2c_client *client)
+{
+       uint8_t buf0[6];
+    int ret = 0;
+       
+#if (0)
+    /* = */
+    buf0[0] = 0x71;
+    buf0[1] = 0x00;//30MHz
+    buf0[2] = 0x01;
+    buf0[3] = 0x07;
+    buf0[4] = 0x0D;
+    buf0[5] = 0x00;
+    
+    ret = i2c_master_send(client, buf0, 6);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+
+    /* = */
+    buf0[0] = 0x76;
+    buf0[1] = 0x01;
+    buf0[2] = 0x1B;
+    ret = i2c_master_send(client, buf0, 3);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+#endif /* (0) */
+    
+
+    /* IC internal power on */
+    buf0[0] = 0x81;
+    ret = i2c_master_send(client, buf0, 1);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+    
+    msleep(120);
+    
+    /* MCU power on */
+    buf0[0] = 0x35;
+    buf0[1] = 0x02;
+    ret = i2c_master_send(client, buf0, 2);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+    
+    msleep(10);
+    
+    /* flash power on */
+    buf0[0] = 0x36;
+    buf0[1] = 0x01;
+    ret = i2c_master_send(client, buf0, 2);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+    
+    msleep(10);
+       
+    ili2102_test(client);
+       msleep(10);
+       
+    /* Start touch panel sensing */
+    buf0[0] = 0x83;
+    ret = i2c_master_send(client, buf0, 1);
+    if(ret < 0) {
+        printk(KERN_ERR "i2c_master_send failed\n");
+    }
+
+       msleep(120);
+        
+       return ret;
+}
+static int ili2102_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+    struct ili2102_ts_data *ts;
+       struct ili2102_platform_data    *pdata = client->dev.platform_data;
+    int ret = 0;
+
+    printk("ili2102 TS probe\n"); //[Step 1]
+    
+    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+        printk(KERN_ERR "ili2102_ts_probe: need 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;
+    }
+    INIT_WORK(&ts->work, ili2102_ts_work_func);
+    ts->client = client;
+    i2c_set_clientdata(client, ts);
+
+       ret = setup_resetPin(client,ts);
+       if(ret)
+       {
+                printk("ili2102 TS setup_resetPin fail\n");
+                goto err_alloc_data_failed;
+       }
+
+       ret=ili2102_chip_Init(ts->client);
+       if(ret<0)
+       {
+               printk("%s:chips init failed\n",__FUNCTION__);
+               goto err_resetpin_failed;
+       }
+
+    /* allocate input device */
+    ts->input_dev = input_allocate_device();
+    if (ts->input_dev == NULL) {
+        ret = -ENOMEM;
+        printk(KERN_ERR "ili2102_ts_probe: Failed to allocate input device\n");
+        goto err_input_dev_alloc_failed;
+    }
+
+       ts->model = pdata->model ? : 801;
+       ts->swap_xy = pdata->swap_xy;
+       ts->x_min = pdata->x_min;
+       ts->x_max = pdata->x_max;
+       ts->y_min = pdata->y_min;
+       ts->y_max = pdata->y_max;
+       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev));
+       snprintf(ts->name, sizeof(ts->name), "gt%d-touchscreen", ts->model);
+       ts->input_dev->phys = ts->phys;
+       ts->input_dev->name = ts->name;
+       ts->input_dev->dev.parent = &client->dev;
+
+       ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_ABS);
+    //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
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 
+                   ts->x_min ? : 0,
+                       ts->x_max ? : 480,
+                       0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
+                       ts->y_min ? : 0,
+                       ts->y_max ? : 800,
+                       0, 0);
+    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 1, 0, 0); //Finger Size
+    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 10, 0, 0); //Touch Size
+
+    /* ts->input_dev->name = ts->keypad_info->name; */
+    ret = input_register_device(ts->input_dev);
+    if (ret) {
+        printk(KERN_ERR "ili2102_ts_probe: Unable to register %s input device\n", ts->input_dev->name);
+        goto err_input_register_device_failed;
+    }
+
+       client->irq = gpio_to_irq(client->irq);
+    if (client->irq) {
+               ret = setup_pendown(client,ts);
+               if(ret)
+               {
+                        printk("ili2102 TS setup_pendown fail\n");
+                        goto err_input_register_device_failed;
+               }
+        ret = request_irq(client->irq, ili2102_ts_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, client->name, ts);
+        if (ret == 0) {
+            DBG("ili2102 TS register ISR (irq=%d)\n", client->irq);
+            ts->use_irq = 1;
+        }
+        else 
+                       dev_err(&client->dev, "request_irq failed\n");
+    }
+    
+    if (!ts->use_irq) {
+        hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+        ts->timer.function = ili2102_ts_timer_func;
+        hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+    }
+#ifdef CONFIG_HAS_EARLYSUSPEND
+    ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+    ts->early_suspend.suspend = ili2102_ts_early_suspend;
+    ts->early_suspend.resume = ili2102_ts_late_resume;
+    register_early_suspend(&ts->early_suspend);
+#endif
+
+    printk(KERN_INFO "ili2102_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
+
+    return 0;
+
+err_input_register_device_failed:
+    input_free_device(ts->input_dev);
+err_resetpin_failed:
+       gpio_free(ts->gpio_reset);
+err_input_dev_alloc_failed:
+    kfree(ts);
+err_alloc_data_failed:
+err_check_functionality_failed:
+    return ret;
+}
+
+static int ili2102_ts_remove(struct i2c_client *client)
+{
+    struct ili2102_ts_data *ts = i2c_get_clientdata(client);
+    unregister_early_suspend(&ts->early_suspend);
+    if (ts->use_irq)
+        free_irq(client->irq, ts);
+    else
+        hrtimer_cancel(&ts->timer);
+    input_unregister_device(ts->input_dev);
+    kfree(ts);
+    return 0;
+}
+
+static int ili2102_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+    int ret;
+    struct ili2102_ts_data *ts = i2c_get_clientdata(client);
+
+    printk("ili2102 TS Suspend\n");
+    
+    if (ts->use_irq)
+        disable_irq(client->irq);
+    else
+        hrtimer_cancel(&ts->timer);
+
+    ret = cancel_work_sync(&ts->work);
+    if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */
+        enable_irq(client->irq);
+
+    // TODO do suspend
+    return 0;
+}
+
+static int ili2102_ts_resume(struct i2c_client *client)
+{
+    struct ili2102_ts_data *ts = i2c_get_clientdata(client);
+
+    ili2102_init_panel(ts);
+    
+    //TODO do resume
+
+    printk("ili2102 TS Resume\n");
+    
+    if (ts->use_irq) {
+        printk("enabling IRQ %d\n", client->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 ili2102_ts_early_suspend(struct early_suspend *h)
+{
+    struct ili2102_ts_data *ts;
+    ts = container_of(h, struct ili2102_ts_data, early_suspend);
+    ili2102_ts_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void ili2102_ts_late_resume(struct early_suspend *h)
+{
+    struct ili2102_ts_data *ts;
+    ts = container_of(h, struct ili2102_ts_data, early_suspend);
+    ili2102_ts_resume(ts->client);
+}
+#endif
+
+#define ILI2102_TS_NAME "ili2102_ts"
+
+static const struct i2c_device_id ili2102_ts_id[] = {
+    { ILI2102_TS_NAME, 0 },
+    { }
+};
+
+static struct i2c_driver ili2102_ts_driver = {
+    .probe      = ili2102_ts_probe,
+    .remove     = ili2102_ts_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+    .suspend    = ili2102_ts_suspend,
+    .resume     = ili2102_ts_resume,
+#endif
+    .id_table   = ili2102_ts_id,
+    .driver = {
+        .name   = ILI2102_TS_NAME,
+    },
+};
+
+static int __devinit ili2102_ts_init(void)
+{
+    printk("ili2102 TS init\n"); //[Step 0]
+    ili2102_wq = create_singlethread_workqueue("ili2102_wq");
+    if (!ili2102_wq)
+        return -ENOMEM;
+    return i2c_add_driver(&ili2102_ts_driver);
+}
+
+static void __exit ili2102_ts_exit(void)
+{
+    printk("ili2102 TS exit\n");
+    i2c_del_driver(&ili2102_ts_driver);
+    if (ili2102_wq)
+        destroy_workqueue(ili2102_wq);
+}
+
+module_init(ili2102_ts_init);
+module_exit(ili2102_ts_exit);
+
+MODULE_DESCRIPTION("ili2102 Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/ili2102_ts.h b/drivers/input/touchscreen/ili2102_ts.h
new file mode 100755 (executable)
index 0000000..6361200
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * drivers/input/touchscreen/xpt2046_cbn_ts.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef __DRIVERS_TOUCHSCREEN_ILI2102_TS_H
+#define __DRIVERS_TOUCHSCREEN_ILI2102_TS_H
+
+#define IOMUX_NAME_SIZE 40
+
+enum touchstate {
+       TOUCH_UP = 0, TOUCH_DOWN = 1,
+};     
+
+struct ili2102_platform_data {
+
+       u16             model;                  /* 8520. */
+       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);
+};
+#endif