porting touch driver form rk28 to rk29sdk
authorsakura <sakura@sakura-desktop.(none)>
Mon, 6 Dec 2010 04:08:35 +0000 (12:08 +0800)
committersakura <sakura@sakura-desktop.(none)>
Mon, 6 Dec 2010 04:08:35 +0000 (12:08 +0800)
drivers/input/touchscreen/hannstar_p1003.c [new file with mode: 0755]

diff --git a/drivers/input/touchscreen/hannstar_p1003.c b/drivers/input/touchscreen/hannstar_p1003.c
new file mode 100755 (executable)
index 0000000..f6f74c0
--- /dev/null
@@ -0,0 +1,341 @@
+/****************************************************************************************
+ * driver/input/touchscreen/hannstar_p1003.c
+ *Copyright    :ROCKCHIP  Inc
+ *Author       :       sfm
+ *Date         :  2010.2.5
+ *This driver use for rk28 chip extern touchscreen. Use i2c IF ,the chip is Hannstar
+ *description£º
+ ********************************************************************************************/
+#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/platform_device.h>
+#include <mach/gpio.h>
+#include <linux/irq.h>
+#include <mach/board.h>
+
+#define MAX_SUPPORT_POINT      2// //  4
+#define Singltouch_Mode     1
+#define sakura_dbg_msg(fmt,...)       do {                                      \
+                                   printk("sakura dbg msg------>"                       \
+                                          " (func-->%s ; line-->%d) " fmt, __func__, __LINE__ , ##__VA_ARGS__); \
+                                  } while(0)
+#define sakura_dbg_report_key_msg(fmt,...)      do{                                                     \
+                                                    printk("sakura report " fmt,##__VA_ARGS__);          \
+                                                }while(0)
+
+struct point_data {    
+       short status;   
+       short x;        
+       short y;
+    short z;
+};
+
+struct multitouch_event{
+       struct point_data point_data[MAX_SUPPORT_POINT];
+       int contactid;
+    int validtouch;
+};
+
+struct ts_p1003 {
+       struct input_dev        *input;
+       char                    phys[32];
+       struct delayed_work     work;
+
+       struct i2c_client       *client;
+    struct multitouch_event mt_event;
+       u16                     model;
+
+       bool            pendown;
+       bool            status;
+       int                     irq;
+       int             has_relative_report;
+       int                     (*get_pendown_state)(void);
+       void            (*clear_penirq)(void);
+};
+
+int p1003_get_pendown_state(void)
+{
+       return 0;
+}
+
+static void p1003_report_event(struct ts_p1003 *ts,struct multitouch_event *tc)
+{
+       struct input_dev *input = ts->input;
+    int i;
+       dev_dbg(&ts->client->dev, "UP\n");
+               
+    for(i=0; i<MAX_SUPPORT_POINT;i++){                 
+        if(tc->point_data[i].status >= 0){                             
+            input_report_abs(input, ABS_MT_TRACKING_ID, i);                                                    
+            input_report_abs(input, ABS_MT_TOUCH_MAJOR, tc->point_data[i].status);                             
+            input_report_abs(input, ABS_MT_WIDTH_MAJOR, 0);    
+            input_report_abs(input, ABS_MT_POSITION_X, tc->point_data[i].x);                           
+            input_report_abs(input, ABS_MT_POSITION_Y, tc->point_data[i].y);                           
+            input_mt_sync(input);      
+
+            printk("\n");
+            if(tc->point_data[i].status == 0)                                  
+               tc->point_data[i].status--;                     
+        }
+    }  
+
+}
+static void p1003_report_single_event(struct ts_p1003 *ts,struct multitouch_event *tc)
+{
+       struct input_dev *input = ts->input;
+    int cid;
+
+    cid = tc->contactid;
+    if(ts->pendown != ts->status){
+        ts->pendown = ts->status;
+        input_report_key(input, BTN_TOUCH, ts->status);
+        input_sync(input);
+        sakura_dbg_report_key_msg("%s x =0x%x,y = 0x%x \n",ts->status?"down":"up",tc->point_data[cid].x,tc->point_data[cid].y);
+    }
+    if(ts->pendown){
+        input_report_abs(input, ABS_X, tc->point_data[cid].x);
+        input_report_abs(input, ABS_Y, tc->point_data[cid].y);
+        input_sync(input);
+    }
+    
+}
+static inline int p1003_read_values(struct ts_p1003 *ts, struct multitouch_event *tc)
+{
+    s32 data;
+    int len = 10;
+    char buf[10];
+    short contactid=0;
+
+    data = i2c_master_normal_recv(ts->client, buf,len, 200*1000);
+
+    if (data < 0 || (buf[0]!=0x04)) {
+       dev_err(&ts->client->dev, "i2c io error: %d or Hannstar read reg failed\n", data);
+       enable_irq(ts->irq);
+       return data;
+    }
+
+    contactid = (buf[1]&0x7C)>>2;
+    tc->contactid = contactid;
+    tc->point_data[contactid].status = buf[1]&0x01; 
+    tc->point_data[contactid].x = ((buf[3]<<8) + buf[2])>>4;
+    tc->point_data[contactid].y = ((buf[5]<<8) + buf[4])>>4;
+    tc->validtouch = buf[1]&0x80;
+    ts->status = tc->point_data[contactid].status;
+//    printk("validtouch =%d,status= %d,contactid =%d\n",tc->validtouch,tc->point_data[contactid].status,contactid);
+    return data;
+}
+
+
+static void p1003_work(struct work_struct *work)
+{
+       struct ts_p1003 *ts =
+               container_of(to_delayed_work(work), struct ts_p1003, work);
+       struct multitouch_event *tc = &ts->mt_event;
+       u32 rt;
+    
+       rt = p1003_read_values(ts,tc);
+    
+    if(rt < 0)
+        goto out;
+
+    p1003_report_single_event(ts,tc);
+    
+ out:
+       if (ts->pendown)
+               schedule_delayed_work(&ts->work,
+                                     msecs_to_jiffies(10));
+       else
+               enable_irq(ts->irq);
+}
+
+static irqreturn_t p1003_irq(int irq, void *handle)
+{
+       struct ts_p1003 *ts = handle;
+       
+#if 1
+       if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
+               disable_irq_nosync(ts->irq);
+               schedule_delayed_work(&ts->work,
+                                     msecs_to_jiffies(10));
+       }
+
+#endif
+       return IRQ_HANDLED;
+}
+
+static void p1003_free_irq(struct ts_p1003 *ts)
+{
+       free_irq(ts->irq, ts);
+       if (cancel_delayed_work_sync(&ts->work)) {
+               /*
+                * Work was pending, therefore we need to enable
+                * IRQ here to balance the disable_irq() done in the
+                * interrupt handler.
+                */
+               enable_irq(ts->irq);
+       }
+}
+
+static int __devinit p1003_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
+{
+       struct ts_p1003 *ts;
+       struct p1003_platform_data *pdata = pdata = client->dev.platform_data;
+       struct input_dev *input_dev;
+       int err;
+
+       if (!pdata) {
+               dev_err(&client->dev, "platform data is required!\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -EIO;
+
+       ts = kzalloc(sizeof(struct ts_p1003), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!ts || !input_dev) {
+               err = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       ts->client = client;
+       ts->irq = client->irq;
+       ts->input = input_dev;
+       ts->status =0 ;// fjp add by 2010-9-30
+       ts->pendown = 0; // fjp add by 2010-10-06
+       
+       INIT_DELAYED_WORK(&ts->work, p1003_work);
+
+       ts->model             = pdata->model;
+
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input0", dev_name(&client->dev));
+
+       input_dev->name = "p1003 Touchscreen";
+       input_dev->phys = ts->phys;
+       input_dev->id.bustype = BUS_I2C;
+
+#if Singltouch_Mode
+       input_dev->evbit[0] = BIT_MASK(EV_ABS)|BIT_MASK(EV_KEY);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_set_abs_params(input_dev,ABS_X,0,1087,0,0);
+       input_set_abs_params(input_dev,ABS_Y,0,800,0,0);
+#else
+       ts->has_relative_report = 0;
+       input_dev->evbit[0] = BIT_MASK(EV_ABS)|BIT_MASK(EV_KEY)|BIT_MASK(EV_SYN);
+       input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       input_dev->keybit[BIT_WORD(BTN_2)] = BIT_MASK(BTN_2); //jaocbchen for dual
+       input_set_abs_params(input_dev, ABS_X, 0, 1087, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 800, 0, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
+       input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
+       input_set_abs_params(input_dev, ABS_HAT0X, 0, 1087, 0, 0);
+       input_set_abs_params(input_dev, ABS_HAT0Y, 0, 800, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_X,0, 1087, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 800, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 10, 0, 0);   
+#endif
+
+       if (pdata->init_platform_hw)
+               pdata->init_platform_hw();
+
+       if (!ts->irq) {
+               dev_dbg(&ts->client->dev, "no IRQ?\n");
+               return -ENODEV;
+       }else{
+               ts->irq = gpio_to_irq(ts->irq);
+       }
+
+       err = request_irq(ts->irq, p1003_irq, 0,
+                       client->dev.driver->name, ts);
+       
+       if (err < 0) {
+               dev_err(&client->dev, "irq %d busy?\n", ts->irq);
+               goto err_free_mem;
+       }
+       
+       if (err < 0)
+               goto err_free_irq;
+#if 0
+       err = set_irq_type(ts->irq,IRQ_TYPE_LEVEL_LOW);
+       if (err < 0) {
+               dev_err(&client->dev, "irq %d busy?\n", ts->irq);
+               goto err_free_mem;
+       }
+       if (err < 0)
+               goto err_free_irq;
+#endif
+       err = input_register_device(input_dev);
+       if (err)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, ts);
+
+       return 0;
+
+ err_free_irq:
+       p1003_free_irq(ts);
+       if (pdata->exit_platform_hw)
+               pdata->exit_platform_hw();
+ err_free_mem:
+       input_free_device(input_dev);
+       kfree(ts);
+       return err;
+}
+
+static int __devexit p1003_remove(struct i2c_client *client)
+{
+       struct ts_p1003 *ts = i2c_get_clientdata(client);
+       struct p1003_platform_data *pdata = client->dev.platform_data;
+
+       p1003_free_irq(ts);
+
+       if (pdata->exit_platform_hw)
+               pdata->exit_platform_hw();
+
+       input_unregister_device(ts->input);
+       kfree(ts);
+
+       return 0;
+}
+
+static struct i2c_device_id p1003_idtable[] = {
+       { "p1003_touch", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, p1003_idtable);
+
+static struct i2c_driver p1003_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "p1003_touch"
+       },
+       .id_table       = p1003_idtable,
+       .probe          = p1003_probe,
+       .remove         = __devexit_p(p1003_remove),
+};
+
+static int __init p1003_init(void)
+{
+       printk("--------> %s <-------------\n",__func__);
+       return i2c_add_driver(&p1003_driver);
+}
+
+static void __exit p1003_exit(void)
+{
+       return i2c_del_driver(&p1003_driver);
+}
+module_init(p1003_init);
+module_exit(p1003_exit);
+MODULE_LICENSE("GPL");
+