summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/vt1609_ts
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/input/touchscreen/vt1609_ts
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/input/touchscreen/vt1609_ts')
-rwxr-xr-xdrivers/input/touchscreen/vt1609_ts/Makefile4
-rwxr-xr-xdrivers/input/touchscreen/vt1609_ts/vt1609_dual.c692
-rwxr-xr-xdrivers/input/touchscreen/vt1609_ts/vt1609_ts.c1481
-rwxr-xr-xdrivers/input/touchscreen/vt1609_ts/vt1609_ts.h301
4 files changed, 2478 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/vt1609_ts/Makefile b/drivers/input/touchscreen/vt1609_ts/Makefile
new file mode 100755
index 00000000..b3e5b2d3
--- /dev/null
+++ b/drivers/input/touchscreen/vt1609_ts/Makefile
@@ -0,0 +1,4 @@
+
+obj-$(CONFIG_TOUCHSCREEN_VT1609) := vt1609_dual.o vt1609_ts.o
+
+
diff --git a/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c b/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c
new file mode 100755
index 00000000..c88872e5
--- /dev/null
+++ b/drivers/input/touchscreen/vt1609_ts/vt1609_dual.c
@@ -0,0 +1,692 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+//#include <linux/spinlock.h>
+#include <linux/input.h>
+#include <linux/cdev.h>
+#include <linux/time.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <linux/gpio.h>
+#include <mach/wmt_iomux.h>
+#include "vt1609_ts.h"
+
+
+//#define _DEBUG_
+
+#undef dbg
+#ifdef _DEBUG_
+#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ## args)
+#else
+#define dbg(fmt, args...)
+#endif
+
+#undef dbg_err
+#define dbg_err(fmt, args...) printk(KERN_ERR "[%s][%d]##ERROR##: " fmt, __func__ , __LINE__, ## args)
+
+#define VT1609_DUAL_VERSION "1.1"
+
+#define DUAL_BUF_LENGTH 17
+#define SINGLE_BUF_LEN 5
+#define MAX_SAMPLE_NUM 5
+#define POLL_TOUT 100
+#define DX_DETLA 4
+#define DX_NUM 5
+
+#define VXY 17
+#define SCALE_X 4
+#define SCALE_Y 2
+#define FILTER_COUNT_T1 2
+#define FILTER_COUNT_T2 5
+#define FILTER_COUNT_2T1 5
+#define SAMPLE_COUNT 4
+#define THRESHOLD_DX 256
+#define THRESHOLD_XY 1300
+#define THRESHOLD_DUAL_CNT 1
+
+#define CHL_X1 0x01
+#define CHL_X2 0x02
+#define CHL_X3 0x03
+#define CHL_Y1 0x04
+#define CHL_Y2 0x05
+#define CHL_Y3 0x06
+
+static int vxy_max_updated = 0;
+static int vx_max = 0;
+static int vy_max = 0;
+
+static int dual_cnt = 0;
+static int prv_dx = 0;
+static int dx1 = 0, dx2 = 0;
+
+static int TwoCT = 0;
+static int FirstCT = 0;
+static int TouchCT = 0 ;
+static int OneTCAfter2 = 0;
+static int TwoTouchFlag = 0;
+static struct vt1603_ts_pos pre,fixpos;
+
+//extern struct vt1603_ts_drvdata *pContext;
+
+struct dual_avg_buf {
+ int num;
+ u32 data[DUAL_BUF_LENGTH];
+};
+
+static struct dual_avg_buf x_buf;
+static struct dual_avg_buf y_buf;
+static struct dual_avg_buf avg_buf;
+
+static int vt1603_ts_get_ux(int *para);
+static int vt1603_ts_get_uy(int *para);
+static int vt1603_ts_get_vx(int *para);
+static int vt1603_ts_get_vy(int *para);
+
+static inline void dual_buf_fill(struct dual_avg_buf *dual_buf, u32 data, int len)
+{
+ dual_buf->data[dual_buf->num % len] = data;
+ dual_buf->num++;
+
+ return ;
+}
+
+static inline u32 dual_buf_avg(struct dual_avg_buf *dual_buf, int len)
+{
+ int i, num;
+ u32 avg = 0;
+ int max, min;
+
+ num = (dual_buf->num < len)? dual_buf->num : len;
+
+ if(num == 1)
+ return dual_buf->data[0];
+ if(num == 2)
+ return (dual_buf->data[0]+dual_buf->data[1])/2;
+
+ max = dual_buf->data[0];
+ min = dual_buf->data[0];
+ for (i = 0; i < num; i++){
+ avg += dual_buf->data[i];
+
+ if(dual_buf->data[i] > max)
+ max = dual_buf->data[i];
+
+ if(dual_buf->data[i] < min)
+ min = dual_buf->data[i];
+ }
+
+ return (avg-max-min )/ (num-2);
+}
+
+static void dual_buf_init(struct dual_avg_buf *dual_buf)
+{
+ memset(dual_buf, 0x00, sizeof(struct dual_avg_buf));
+ return ;
+}
+
+static inline void vt1603_ts_report_dual_pos(struct vt1603_ts_drvdata *ts_drv,
+ struct vt1603_ts_pos *fst,struct vt1603_ts_pos *lst)
+{
+ struct vt1603_ts_pos p1 = *fst;
+ struct vt1603_ts_pos p2 = *lst;
+
+ vt1603_ts_pos_calibration(ts_drv,&p1);
+ vt1603_ts_pos_calibration(ts_drv,&p2);
+ //dbg("Caled pos1 (%d, %d), pos2 (%d, %d)\n", p1.x, p1.y, p2.x, p2.y);
+
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p1.x);
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p1.y);
+ input_mt_sync(ts_drv->input);
+
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_X, p2.x);
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, p2.y);
+ input_mt_sync(ts_drv->input);
+
+ input_sync(ts_drv->input);
+
+ return;
+}
+
+static inline void vt1603_ts_auto_mode(struct vt1603_ts_drvdata *ts_drv)
+{
+ vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x08);
+ /* auto position conversion mode and panel type config */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1);
+ /* disable pen up/down detection, it is a MUST opearetion */
+ vt1603_set_reg8(ts_drv, 0xC8, 0x7F);
+
+ return;
+}
+
+static inline int select_channel(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ switch(chl){
+ case CHL_X1://select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ case CHL_X2://select x2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x04);
+ break;
+ case CHL_X3://select x3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x00);
+ break;
+ case CHL_Y1://select y1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x07);
+ break;
+ case CHL_Y2://select y2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x06);
+ break;
+ case CHL_Y3://select y3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x03);
+ break;
+ default://default select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int select_x_channel(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ switch(chl){
+ case CHL_X1://select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x07);
+ break;
+ case CHL_X2://select x2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x06);
+ break;
+ case CHL_X3://select x3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x21);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x03);
+ break;
+ case CHL_Y1://select y1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+
+ break;
+ case CHL_Y2://select y2
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x04);
+ break;
+ case CHL_Y3://select y3
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x00);
+ break;
+ default://default select x1
+ vt1603_set_reg8(ts_drv, 0xc6, 0x12);
+ vt1603_set_reg8(ts_drv, 0xc7, 0x05);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int get_channel_data(struct vt1603_ts_drvdata *ts_drv,int chl)
+{
+ int i = 0;
+ int sum = 0;
+ int buf[MAX_SAMPLE_NUM] = {0};
+ u32 now = 0;
+ u8 tmp = 0;
+
+ if(ts_drv->dual_dev.exch)
+ select_x_channel(ts_drv,chl);
+ else
+ select_channel(ts_drv,chl);
+
+ for (i = 0; i < ts_drv->dual_dev.SAMPLE_CNT; i++) {
+ vt1603_clrbits(ts_drv, VT1603_INTS_REG, 0x0f);
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x10);
+ udelay(100);
+ now = jiffies;
+ while (time_before(jiffies, now + msecs_to_jiffies(POLL_TOUT))) {
+ tmp = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if (tmp & BIT0) {
+ buf[i] = vt1603_get_reg8(ts_drv, 0xce);
+ tmp = (vt1603_get_reg8(ts_drv, 0xcf) & 0x0f);
+ buf[i] |= (tmp << 8);
+ sum += buf[i];
+ goto next;
+ }
+ }
+ printk("VT1609 %s timeout!\n", __func__);
+ return 0;
+
+ next:
+ ;//printk("CHL %d buf[%d] is %d\n", chl, i, buf[i]);
+ }
+
+ return sum/ts_drv->dual_dev.SAMPLE_CNT;
+
+}
+
+
+static inline int vt1603_get_paramters(struct vt1603_ts_drvdata *ts_drv, int *para)
+{
+ /* change to manual mode now */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00);
+ /* set prechare to 0x10 */
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ /* get parameters now */
+ para[0] = get_channel_data(ts_drv, CHL_X1);
+ para[1] = get_channel_data(ts_drv, CHL_X2);
+ para[2] = get_channel_data(ts_drv, CHL_Y1);
+ para[3] = get_channel_data(ts_drv, CHL_Y2);
+
+ para[4] = get_channel_data(ts_drv, CHL_X3);
+ para[5] = get_channel_data(ts_drv, CHL_Y3);
+
+ /* reset adc, this is a MUST operation */
+ vt1603_set_reg8(ts_drv, 0xc8, 0x8f);
+ vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0);
+
+ return 0;
+}
+
+static int vt1603_get_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy)
+{
+ int i;
+ int xbuf[5] ={0}, ybuf[5] ={0};
+ int sum_vx = 0,sum_vy = 0;
+ int max_vx = 0,min_vx = 0;
+ int max_vy = 0,min_vy = 0;
+
+ /* change to manual mode now */
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, 0x00);
+ /* set prechare to 0x10 */
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ for(i=0; i<5; i++){
+ xbuf[i] = get_channel_data(ts_drv,CHL_X3);
+ ybuf[i] = get_channel_data(ts_drv,CHL_Y3);
+ sum_vx += xbuf[i];
+ sum_vy += ybuf[i];
+ }
+
+ max_vx = min_vx = xbuf[0];
+ max_vy = min_vy = ybuf[0];
+
+ for(i=0; i<5; i++){
+ if(xbuf[i] > max_vx)
+ max_vx = xbuf[i];
+
+ if(xbuf[i] < min_vx)
+ min_vx = xbuf[i];
+
+ if(ybuf[i] > max_vy)
+ max_vy = ybuf[i];
+
+ if(ybuf[i] < min_vy)
+ min_vy = ybuf[i];
+ }
+ *vx = (sum_vx - max_vx - min_vx)/3;
+ *vy = (sum_vy - max_vy - min_vy)/3;
+ dbg("updated vx_max=%d; vy_max=%d\n",*vx, *vy);
+ /* reset adc, this is a MUST operation */
+ vt1603_set_reg8(ts_drv, 0xc8, 0x8f);
+ vt1603_set_reg8(ts_drv, 0xc0, BIT6 | BIT5 | BIT0);
+
+ return 0;
+}
+
+static inline int vt1603_ts_get_ux(int *para)
+{
+ return abs(para[1] - para[0]);
+}
+
+static inline int vt1603_ts_get_uy(int *para)
+{
+ return abs(para[3] - para[2]);
+}
+
+static inline int vt1603_ts_get_vx(int *para)
+{
+ return abs(vx_max - para[4]);
+}
+
+static inline int vt1603_ts_get_vy(int *para)
+{
+ return abs(vy_max - para[5]);
+}
+
+static inline int vt1603_ts_nTouch(struct vt1603_ts_drvdata *ts_drv, int *para)
+{
+ int ux, uy, vx, vy;
+
+ ux = vt1603_ts_get_ux(para);
+ uy = vt1603_ts_get_uy(para);
+ vx = vt1603_ts_get_vx(para);
+ vy = vt1603_ts_get_vy(para);
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+
+ if ((vx <= 5) && (vy <= 5)){
+ dual_cnt = 0;
+ return Single_TOUCH;
+ }else if ((vx >= ts_drv->dual_dev.vxy) || (vy >= ts_drv->dual_dev.vxy)){
+ dual_cnt++;
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+ return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH;
+ }else if (((vx > 5) || (vy > 5)) && ((ux >= 2 * ts_drv->dual_dev.vxy) || (uy >= 2 * ts_drv->dual_dev.vxy))){
+ dual_cnt++;
+ //printk("ux:%-3d, uy:%-3d, vx:%-3d, vy:%-3d\n", ux, uy, vx, vy);
+ return (dual_cnt > THRESHOLD_DUAL_CNT)? Multi_TOUCH : Single_TOUCH;
+ }else{
+ dual_cnt = 0;
+ return Single_TOUCH;
+ }
+
+}
+
+static int pos_fix(const int limit, int p)
+{
+ if (p > limit) p = limit;
+ if (p < 0) p = 0;
+
+ return (u16)(p & 0xffff);
+}
+
+static int vt1603_ts_update_vxy(struct vt1603_ts_drvdata *ts_drv, int *vx, int *vy)
+{
+ u8 val;
+ int timeout = 100;
+
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ while (timeout-- && val != 0x02) {
+ msleep(20);
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ }
+
+ if(!timeout){
+ dbg_err("get vx_max/vy_max failed!\n");
+ goto out;
+ }
+
+ vt1603_get_vxy(ts_drv, vx,vy);
+ dbg("update vx_max:%d, vy_max:%d\n", vx_max, vy_max);
+
+out:
+ vt1603_set_reg8(ts_drv, VT1603_INTS_REG, 0x0F);
+
+ return 0;
+}
+
+void vt1603_ts_dual_support(struct work_struct* dwork)
+{
+ int nTouch = 0;
+ int para[6] = { 0 };
+ //unsigned long flags = 0;
+ int vx = 0, vy = 0, dx = 0;
+ struct vt1603_ts_pos p,pos1, pos2;
+ struct vt1603_ts_drvdata *ts_drv = NULL;
+ u8 int_sts = 0;
+
+ ts_drv = container_of(dwork, struct vt1603_ts_drvdata, dual_work.work);
+
+ //spin_lock_irqsave(&ts_drv->spinlock, flags);
+ mutex_lock(&ts_drv->ts_mutex);
+
+ int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if (int_sts & BIT4 || ts_drv->earlysus) {
+ if (jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < TS_DEBOUNCE && !ts_drv->earlysus) {
+ dbg("vt1603 ts debouncing?...\n");
+ //vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F);
+ goto next_loop;
+ }
+ dbg("======= penup ======\n");
+
+ /* update vx_max/vy_max only when first penup */
+ if(!vxy_max_updated){
+ vxy_max_updated ++;
+ vt1603_ts_update_vxy(ts_drv, &vx_max, &vy_max);
+ }
+ vt1603_ts_auto_mode(ts_drv);
+ /* vt1603 gpio1 as IRQ output */
+ vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);
+ input_mt_sync(ts_drv->input);
+ input_sync(ts_drv->input);
+ ts_drv->pen_state = TS_PENUP_STATE;
+ #ifdef TOUCH_KEY
+ vt1603_ts_report_key(ts_drv);
+ #endif
+ dual_buf_init(&avg_buf);
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+
+ dx2 = 0;
+ dx1 = 0;
+ pre.x = 0;
+ pre.y = 0;
+ FirstCT = 0;
+ TwoCT = 0;
+ TouchCT = None_TOUCH;
+ OneTCAfter2 = 0;
+ TwoTouchFlag = 0;
+ vt1603_clr_ts_irq(ts_drv, int_sts & 0x0F);
+
+ if(!ts_drv->earlysus)
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return;
+ }
+
+ ts_drv->ts_stamp = jiffies;
+ ts_drv->pen_state = TS_PENDOWN_STATE;
+ vt1603_get_paramters(ts_drv, para);
+ vt1603_ts_auto_mode(ts_drv);
+ //vt1603_clr_ts_irq(ts_drv, 0x0F & int_sts);
+
+ nTouch = vt1603_ts_nTouch(ts_drv, para);
+ if(nTouch == Single_TOUCH){
+ p.x = (para[0] + para[1]) / 2;
+ p.y = (para[2] + para[3]) / 2;
+
+ if(TwoTouchFlag ==0 && FirstCT < ts_drv->dual_dev.F1_CNT){
+ FirstCT ++;
+ dbg("Filter First %d Single Touch\n",FirstCT);
+ goto next_loop;
+
+ }else if(TwoTouchFlag == 1 && OneTCAfter2 < ts_drv->dual_dev.F2T1_CNT){
+ dbg("Filter First %d pointer when back to single touch from dual touch\n",OneTCAfter2);
+ dx1 = 0;
+ dx2 = 0;
+ TwoCT = 0;
+ OneTCAfter2 ++;
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+ dual_buf_init(&avg_buf);
+ goto next_loop;
+
+ }else if(p.x > vx_max || p.y > vy_max){
+ dbg("Pos (%d,%d) beyond vx_max or vy_max\n",p.x,p.y);
+ goto next_loop;
+
+ }else if((pre.x!=0 && pre.y!=0) && (abs(pre.x-p.x) > THRESHOLD_XY||abs(pre.y-p.y) > THRESHOLD_XY )){
+ dbg("Threhold Filter Pos (%-4d,%-4d) ,dx=%-4d,dy=%-4d\n",p.x,p.y,abs(pre.x-p.x),abs(pre.y-p.y));
+ pre.x = p.x;
+ pre.y = p.y;
+ goto next_loop;
+
+ }else{
+ dual_buf_fill(&x_buf, p.x, SINGLE_BUF_LEN);
+ dual_buf_fill(&y_buf, p.y, SINGLE_BUF_LEN);
+ p.x = dual_buf_avg(&x_buf, SINGLE_BUF_LEN);
+ p.y = dual_buf_avg(&y_buf, SINGLE_BUF_LEN);
+ dbg("Report PHY Pos (%-4d,%-4d)\n",p.x,p.y);
+ pre.x = p.x;
+ pre.y = p.y;
+ #ifdef TOUCH_KEY
+ if(vt1603_ts_get_key(ts_drv, p))
+ goto next_loop;
+ #endif
+
+ vt1603_ts_report_pos(ts_drv, &p);
+
+ TwoCT = 0;
+ TouchCT = Single_TOUCH;
+ OneTCAfter2 = 0;
+ TwoTouchFlag = 0;
+ goto next_loop;
+ }
+ }
+ else if(nTouch == Multi_TOUCH){
+ vx = vt1603_ts_get_vx(para);
+ vy = vt1603_ts_get_vy(para);
+ dx = ts_drv->dual_dev.scale_y * vy + ts_drv->dual_dev.scale_x * vx;
+
+ if(dx1 && dx2)
+ dx = (dx+dx1+dx2)/3;
+ dx2 = dx1;
+ dx1 = dx;
+ dbg("vx=%-3d, vy=%-3d, dx=%-d, Ddx=%-3d\n",vx,vy,dx,abs(prv_dx-dx));
+
+ if(TwoCT < ts_drv->dual_dev.F2_CNT){
+ TwoCT ++;
+ dual_buf_init(&avg_buf);
+ dbg("Filter The First %d Dual Touch\n",TwoCT);
+ goto next_loop;
+
+ }else if (prv_dx!=0 && (abs(prv_dx - dx) > ts_drv->dual_dev.THR_MAX_DX)){
+ dbg("Threhold Filter Dual Touch dx=%d\n",abs(prv_dx - dx) );
+ prv_dx = dx;
+ goto next_loop;
+
+ }else{
+ //process and report dual touch data
+ dual_buf_fill(&avg_buf, dx, DUAL_BUF_LENGTH);
+ dx = dual_buf_avg(&avg_buf, DUAL_BUF_LENGTH);
+
+ if(abs(prv_dx - dx) < ts_drv->dual_dev.THR_MIN_DX){
+ //printk("Replace with last dx Ddx=%d\n",abs(prv_dx - dx));
+ dx = prv_dx;
+ }
+
+ if(TwoTouchFlag==0 && TouchCT==Single_TOUCH){//Single Touch ->Multi Touch
+ fixpos = pre;
+ //printk("Touch(%-4d,%-4d) 1--->2\n",pre.x,pre.y);
+ }else if(TwoTouchFlag==0 && TouchCT==None_TOUCH){//Multi Touch from the beginning
+ fixpos.x = vx_max/2;
+ fixpos.y = vy_max/2;
+ //printk("Touch(%-4d,%-4d) 2--->2\n",pos1.x, pos1.y);
+ }
+
+ pos1 = fixpos;
+ pos2.x = fixpos.x;
+ if(fixpos.y > vy_max/2)
+ pos2.y = pos_fix(vy_max, (fixpos.y - 150 - dx*DX_DETLA/DX_NUM));
+ else
+ pos2.y = pos_fix(vy_max, (fixpos.y + 150 + dx*DX_DETLA/DX_NUM));
+
+ dbg("PHY dx=%d, pos1.y=%d, pos2.y=%d\n", dx, pos1.y, pos2.y);
+ vt1603_ts_report_dual_pos(ts_drv, &pos1, &pos2);
+
+ prv_dx = dx;
+ TouchCT = Multi_TOUCH;
+ TwoTouchFlag = 1;
+ OneTCAfter2 = 0;
+ #ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ set_key_led_gpio(ts_drv,HIGH);
+ #endif
+ goto next_loop;
+ }
+ }
+ else{
+ dbg_err("Main Loop Error!\n");
+ }
+
+next_loop:
+ queue_delayed_work(ts_drv->workqueue, &ts_drv->dual_work, msecs_to_jiffies(20));
+ vt1603_clr_ts_irq(ts_drv, 0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return ;
+}
+
+int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv)
+{
+ int ret = 0;
+ //unsigned long flags = 0;
+ int retries = 20;
+ u8 val = 0;
+
+ if (ts_drv == NULL) {
+ printk(KERN_ERR "VT1609 TouchScreen Driver Does Not Exsit!\n");
+ ret = -1;
+ goto out;
+ }
+
+ //spin_lock_irqsave(&ts_drv->spinlock, flags);
+ mutex_lock(&ts_drv->ts_mutex);
+
+ while (retries--) {
+ val = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ if ((val & BIT4) == 0) {
+ printk(KERN_ERR "Do not keep in touching, when vt1609 driver to be installed!\n");
+ msleep(20);
+ continue ;
+ }
+
+ val = vt1603_get_reg8(ts_drv, VT1603_CR_REG);
+ if ( val != 0x02) {
+ printk(KERN_ERR "VT1609 is not working in TS mode now!reg: C1=0x%02x\n",val);
+ msleep(10);
+ continue;
+ }
+
+ break ;
+ }
+
+ if (retries == 0) {
+ printk(KERN_ERR "Enable VT1609 Dual Touch Support Failed!\n");
+ ret = -1;
+ goto out;
+ }
+
+
+ vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, 0x04);
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x10);
+ vt1603_get_vxy(ts_drv, &vx_max, &vy_max);
+ vt1603_ts_auto_mode(ts_drv);
+ vt1603_clr_ts_irq(ts_drv, BIT0 | BIT2 | BIT3);
+
+ dual_buf_init(&avg_buf);
+ dual_buf_init(&x_buf);
+ dual_buf_init(&y_buf);
+
+ printk("VT1609 Dual Touch vx_max=%d,vy_max=%d, vxy=%d ver=%s\n",vx_max, vy_max,ts_drv->dual_dev.vxy,VT1609_DUAL_VERSION);
+out:
+ vt1603_clr_ts_irq(ts_drv, 0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return ret;
+}
+
+void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv)
+{
+ vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_drv->pdata->sclk_div);
+ vt1603_set_reg8(ts_drv, VT1603_TSPC_REG, 0x20);
+ printk("VT1609 Dual Touch Support Disabled.\n");
+
+ return ;
+}
+
+
diff --git a/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c b/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c
new file mode 100755
index 00000000..f41634fc
--- /dev/null
+++ b/drivers/input/touchscreen/vt1609_ts/vt1609_ts.c
@@ -0,0 +1,1481 @@
+/*
+ * vt1603_mt_i2c.c: VT1603A Touch-Panel Controller and SAR-ADC 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
+ *
+ * History: 2011.Jan.21st, version: 1.00
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+//#include <linux/spinlock.h>
+#include <linux/input.h>
+#include <linux/random.h>
+#include <linux/cdev.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <mach/wmt_iomux.h>
+
+#include "vt1609_ts.h"
+
+
+//#define VT1609_DEBUG
+
+#undef dbg
+#ifdef VT1609_DEBUG
+#define dbg(fmt, args...) printk(KERN_ERR "[%s][%d]: " fmt, __func__ , __LINE__, ##args)
+#else
+#define dbg(fmt, args...)
+#endif
+
+static struct vt1603_fifo px;
+static struct vt1603_fifo py;
+static struct class *vt1603_ts_class;
+static struct vt1603_ts_pos pre_pos;
+static struct vt1603_ts_cal_info g_CalcParam;
+struct vt1603_ts_drvdata *pContext = NULL;
+
+static int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv);
+static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv);
+
+#ifdef TOUCH_KEY
+static unsigned int key_codes[TOUCH_KEY_NUM] = {
+ [0] = KEY_SEARCH,
+ [1] = KEY_BACK,
+ [2] = KEY_HOME,
+ [3] = KEY_MENU,
+};
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void vt1603ts_early_suspend(struct early_suspend *h);
+static void vt1603ts_late_resume(struct early_suspend *h);
+#endif
+
+#ifdef TOUCH_KEY
+static int setup_led_gpio(struct vt1603_ts_drvdata *ts_drv)
+{
+ if (ts_drv->ledgpio >= 0)
+ gpio_direction_output(ts_drv->ledgpio, 0);
+
+ return 0;
+}
+
+int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv, int val)
+{
+ if (ts_drv->ledgpio >= 0) {
+ if(val)
+ gpio_direction_output(ts_drv->ledgpio, 1);
+ else
+ gpio_direction_output(ts_drv->ledgpio, 0);
+ }
+
+ return 0;
+}
+
+static void led_timer_func(unsigned long data)
+{
+ set_key_led_gpio((struct vt1603_ts_drvdata *)data,LOW);
+ return;
+}
+
+#endif
+
+
+/*
+ * vt1603_set_reg8 - set register value of vt1603
+ * @ts_drv: vt1603 driver data
+ * @reg: vt1603 register address
+ * @val: value register will be set
+ */
+inline int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val)
+{
+ int ret =0;
+ if (ts_drv->tdev)
+ ret = ts_drv->tdev->reg_write(ts_drv->tdev,reg,val);
+
+ if(ret)
+ printk("vt1609 ts write error, errno%d\n", ret);
+
+ return ret;
+}
+
+/*
+ * vt1603_get_reg8 - get register value of vt1603
+ * @ts_drv: vt1603 driver data
+ * @reg: vt1603 register address
+ */
+inline u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg)
+{
+ u8 val = 0;
+ int ret = 0;
+
+ if (ts_drv->tdev)
+ ret = ts_drv->tdev->reg_read(ts_drv->tdev,reg,&val);
+
+ if (ret)
+ printk("vt1609 ts read error, errno%d\n", ret);
+
+ return val;
+}
+
+
+#ifdef VT1609_DEBUG
+/*
+ * vt1603_reg_dump - dubug function, for dump vt1603 related registers
+ * @ts_drv: vt1603 driver data
+ */
+static void vt1603_reg_dump(struct vt1603_ts_drvdata *ts_drv)
+{
+ u8 i;
+ for (i = 0; i < 15; i++)
+ dbg("reg[%d]:0x%02X, reg[%d]:0x%02X\n",
+ i, vt1603_get_reg8(ts_drv, i), i + 0xC0, vt1603_get_reg8(ts_drv, i + 0xC0));
+}
+#endif
+
+/*
+ * vt1603_setbits - write bit1 to related register's bit
+ * @ts_drv: vt1603 driver data
+ * @reg: vt1603 register address
+ * @mask: bit setting mask
+ */
+inline void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask)
+{
+ u8 tmp = 0;
+ tmp = vt1603_get_reg8(ts_drv, reg) | mask;
+ vt1603_set_reg8(ts_drv, reg, tmp);
+
+ return;
+}
+
+
+/*
+ * vt1603_clrbits - write bit0 to related register's bit
+ * @ts_drv: vt1603 driver data
+ * @reg: vt1603 register address
+ * @mask:bit setting mask
+ */
+inline void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask)
+{
+ u8 tmp = vt1603_get_reg8(ts_drv, reg) & (~mask);
+ vt1603_set_reg8(ts_drv, reg, tmp);
+
+ return;
+}
+
+/*
+ * vt1603_clr_ts_irq - clear touch panel pen down/up and
+ * conversion end/timeout interrupts
+ * @ts_drv: vt1603 driver data
+ * @mask: which interrupt will be cleared
+ */
+inline int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask)
+{
+ vt1603_setbits(ts_drv, VT1603_INTS_REG, mask);
+ return 0;
+}
+
+
+/*
+ * Enable I2S CLK, wmt-i2s.c have done this.
+ */
+static void vt1603_ts_clk_enable(void)
+{
+#if 0
+ /* set to 11.288MHz */
+ auto_pll_divisor(DEV_I2S, CLK_ENABLE , 0, 0);
+ auto_pll_divisor(DEV_I2S, SET_PLLDIV, 1, 11288);
+ /*clock = auto_pll_divisor(DEV_I2S, GET_FREQ , 0, 0);
+ info("%s : clock=%d \n" , __func__, clock);*/
+
+ /* Enable BIT4:ARFP clock, BIT3:ARF clock */
+ PMCEU_VAL |= (BIT4 | BIT3);
+
+ /* Enable BIT2:AUD clock */
+ PMCE3_VAL |= BIT2;
+
+ /* disable GPIO and Pull Down mode */
+ GPIO_CTRL_GP10_I2S_BYTE_VAL &= ~0xFF;
+ GPIO_CTRL_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2);
+
+ GPIO_PULL_EN_GP10_I2S_BYTE_VAL &= ~0xFF;
+ GPIO_PULL_EN_GP27_BYTE_VAL &= ~(BIT0 | BIT1 | BIT2);
+
+ /* set to 2ch input, 2ch output */
+ GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~(BIT3 | BIT17 | BIT19 | BIT20 | BIT22);
+ GPIO_PIN_SHARING_SEL_4BYTE_VAL |= (BIT0 | BIT2 | BIT16 | BIT18 | BIT21);
+#endif
+ return;
+}
+
+/*
+ * vt1603_setup_ts_mode - switch to VT1603 TS mode
+ * @ts_drv: vt1603 driver data
+ */
+static int vt1603_setup_ts_mode(struct vt1603_ts_drvdata *ts_drv)
+{
+ int ret = 0;
+ struct vt1603_ts_platform_data *ts_pdata;
+
+ ts_pdata = ts_drv->pdata;
+ ret |= vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div);
+ if (ts_pdata->panel_type == PANEL_TYPE_4WIRED)
+ ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1);
+ else
+ ret |= vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0);
+
+ vt1603_clr_ts_irq(ts_drv, 0x0f);
+
+ return (ret < 0)? -1 : 0;
+
+}
+
+
+static int vt1603_fifo_push(struct vt1603_fifo *Fifo, int Data)
+{
+ Fifo->buf[Fifo->head] = Data;
+ Fifo->head++;
+ if(Fifo->head >= VT1603_FIFO_LEN){
+ Fifo->head = 0;
+ Fifo->full = 1;
+ }
+
+ return 0;
+}
+
+static int vt1603_fifo_avg(struct vt1603_fifo Fifo, int *Data)
+{
+ int i=0;
+ int Sum=0,Max=0,Min=0;
+
+ if(!Fifo.full && !Fifo.head)//FIFO is empty
+ return 0;
+
+ if(!Fifo.full ){
+ for(i=0; i<Fifo.head; i++)
+ Sum += Fifo.buf[i];
+
+ *Data = Sum/Fifo.head;
+ return 0;
+ }
+
+ Max = Fifo.buf[0];
+ Min = Fifo.buf[0];
+ for(i=0; i<VT1603_FIFO_LEN; i++){
+ Sum += Fifo.buf[i];
+
+ if(Max < Fifo.buf[i])
+ Max = Fifo.buf[i];
+
+ if(Min > Fifo.buf[i])
+ Min = Fifo.buf[i];
+ }
+ Sum -= Max;
+ Sum -= Min;
+ *Data = Sum/(VT1603_FIFO_LEN-2);
+
+ return 0;
+
+}
+
+
+inline int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal)
+{
+ int x, y;
+
+ x = (g_CalcParam.a1 * to_cal->x + g_CalcParam.b1 * to_cal->y +
+ g_CalcParam.c1) / g_CalcParam.delta;
+ y = (g_CalcParam.a2 * to_cal->x + g_CalcParam.b2 * to_cal->y +
+ g_CalcParam.c2) / g_CalcParam.delta;
+
+ /* pos check */
+ if (x < 0)
+ x = 0;
+ if (y < 0)
+ y = 0;
+ if (x > ts_drv->resl_x)
+ x = ts_drv->resl_x - 1;
+ if (y > ts_drv->resl_y)
+ y = ts_drv->resl_y - 1;
+
+ if (ts_drv->lcd_exchg) {
+ int tmp;
+ tmp = x;
+ x = y;
+ y = ts_drv->resl_x - tmp;
+ }
+
+ to_cal->x = x;
+ to_cal->y = y;
+
+ return 0;
+}
+
+static inline void vt1603_ts_set_rawdata(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *pos)
+{
+ ts_drv->raw_x = pos->x;
+ ts_drv->raw_y = pos->y;
+
+ return;
+}
+
+inline void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos)
+{
+ vt1603_ts_set_rawdata(ts_drv,pos);
+ vt1603_ts_pos_calibration(ts_drv,pos);
+
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_X, pos->x);
+ input_report_abs(ts_drv->input, ABS_MT_POSITION_Y, pos->y);
+ input_mt_sync(ts_drv->input);
+ input_sync(ts_drv->input);
+
+ return;
+}
+
+#ifdef TOUCH_KEY
+void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv)
+{
+ if(ts_drv->touch_key_used ){
+
+ if(ts_drv->ledgpio >= 0 )
+ mod_timer(&ts_drv->led_timer, jiffies+10*HZ);
+
+ if(ts_drv->key_pressed && ts_drv->key_idx < _MAX_NUM ){
+ input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 1);
+ input_sync(ts_drv->input);
+ input_report_key(ts_drv->input, key_codes[ts_drv->key_idx], 0);
+ input_sync(ts_drv->input);
+ dbg("report as key event %d \n",ts_drv->key_idx);
+ }
+ }
+
+ return;
+}
+
+inline int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos)
+{
+ if(ts_drv->touch_key_used){
+
+ if(pos.y > ts_drv->tsc_key.low && pos.y < ts_drv->tsc_key.upper){
+
+ ts_drv->key_pressed = 1;
+ if(pos.x>(ts_drv->tsc_key.key[_SEARCH].pos-ts_drv->tsc_key.delta) &&
+ pos.x<(ts_drv->tsc_key.key[_SEARCH].pos+ts_drv->tsc_key.delta)){
+ ts_drv->key_idx = ts_drv->tsc_key.key[_SEARCH].idx;
+ }
+ else if(pos.x>(ts_drv->tsc_key.key[_BACK].pos-ts_drv->tsc_key.delta) &&
+ pos.x<(ts_drv->tsc_key.key[_BACK].pos+ts_drv->tsc_key.delta)){
+ ts_drv->key_idx = ts_drv->tsc_key.key[_BACK].idx;
+ }
+ else if(pos.x>(ts_drv->tsc_key.key[_HOME].pos-ts_drv->tsc_key.delta) &&
+ pos.x<(ts_drv->tsc_key.key[_HOME].pos+ts_drv->tsc_key.delta)){
+ ts_drv->key_idx = ts_drv->tsc_key.key[_HOME].idx;
+ }
+ else if(pos.x>(ts_drv->tsc_key.key[_MENU].pos-ts_drv->tsc_key.delta) &&
+ pos.x<(ts_drv->tsc_key.key[_MENU].pos+ts_drv->tsc_key.delta)){
+ ts_drv->key_idx = ts_drv->tsc_key.key[_MENU].idx;
+ }
+ else{
+ ts_drv->key_idx = _MAX_NUM;
+ }
+
+ if(ts_drv->key_idx < _MAX_NUM && ts_drv->ledgpio >= 0)
+ set_key_led_gpio(ts_drv,HIGH);
+
+ return 1;
+ }
+
+ if(ts_drv->ledgpio >= 0)
+ set_key_led_gpio(ts_drv,HIGH);
+ }
+
+ ts_drv->key_pressed= 0;
+
+ return 0 ;
+}
+
+#endif
+
+
+/*
+ * vt1603_ts_get_pos - get touch panel touched position from vt1603
+ * conversion register
+ * @ts_drv: vt1603 driver data
+ * @pos: vt1603 touch panel touched point conversion data
+ */
+static inline void vt1603_ts_get_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos)
+{
+ u8 datal, datah;
+
+ /* get x-position */
+ datal = vt1603_get_reg8(ts_drv, VT1603_XPL_REG);
+ datah = vt1603_get_reg8(ts_drv, VT1603_XPH_REG);
+ pos->x = ADC_DATA(datal, datah);
+
+ /* get y-positin */
+ datal = vt1603_get_reg8(ts_drv, VT1603_YPL_REG);
+ datah = vt1603_get_reg8(ts_drv, VT1603_YPH_REG);
+ pos->y = ADC_DATA(datal, datah);
+ vt1603_clr_ts_irq(ts_drv, BIT0);
+
+ return;
+}
+
+/*
+ * vt1603_ts_isPendown - get touch panel pen state from vt1603
+ * interrup status register
+ * @ts_drv: vt1603 driver data
+ */
+static inline int vt1603_ts_isPendown(struct vt1603_ts_drvdata *ts_drv)
+{
+ u8 state = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+
+ if (state & BIT4)
+ return TS_PENUP_STATE;
+ else
+ return TS_PENDOWN_STATE;
+}
+
+
+static inline int vt1603_pos_avg(struct vt1603_ts_pos *pos)
+{
+ vt1603_fifo_push(&px, pos->x);
+ vt1603_fifo_push(&py, pos->y);
+ vt1603_fifo_avg(px, &pos->x);
+ vt1603_fifo_avg(py, &pos->y);
+
+ return 0;
+}
+
+static int vt1603_pos_cleanup(void)
+{
+ px.full = 0;
+ px.head = 0;
+
+ py.full = 0;
+ py.head = 0;
+
+ return 0;
+}
+
+static void vt1603_read_loop(struct work_struct* dwork)
+{
+ struct vt1603_ts_drvdata *ts_drv=NULL;
+ struct vt1603_ts_pos pos;
+
+ ts_drv = container_of(dwork, struct vt1603_ts_drvdata, read_work.work);
+ ts_drv->pen_state= vt1603_ts_isPendown(ts_drv);
+ if((ts_drv->pen_state == TS_PENUP_STATE) ||ts_drv->earlysus){
+ vt1603_clr_ts_irq(ts_drv, 0x0F);
+ if(jiffies_to_msecs(jiffies - ts_drv->ts_stamp) < 80 && !ts_drv->earlysus){
+ //dbg("Debounceing@@@@@@@@\n");
+ goto next_loop;
+ }
+
+ dbg("============== penup ==============\n");
+ vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */
+ input_mt_sync(ts_drv->input);
+ input_sync(ts_drv->input);
+ #ifdef TOUCH_KEY
+ vt1603_ts_report_key(ts_drv);
+ #endif
+ pre_pos.x = 0;
+ pre_pos.y = 0;
+ ts_drv->hcnt = 0;
+ vt1603_pos_cleanup();
+
+ if(!ts_drv->earlysus)
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+
+ return;
+ }
+
+ ts_drv->ts_stamp = jiffies;
+ vt1603_ts_get_pos(ts_drv, &pos);
+
+ //Filter the first N point
+ if(ts_drv->hcnt < VT1603_FILTER_HEAD_COUNT){
+ ts_drv->hcnt++;
+ goto next_loop;
+ }
+
+ /* 平滑滤波*/
+ if((pre_pos.x != 0 && pre_pos.y != 0)&&(abs(pre_pos.x-pos.x) > VT1603_JITTER_THRESHOLD||abs(pre_pos.y-pos.y) > VT1603_JITTER_THRESHOLD)){
+ pre_pos.x = pos.x;
+ pre_pos.y = pos.y;
+ goto next_loop;
+ }
+#ifdef TOUCH_KEY
+ if(vt1603_ts_get_key(ts_drv,pos))
+ goto next_loop;
+#endif
+
+ vt1603_pos_avg(&pos);
+ pre_pos.x = pos.x;
+ pre_pos.y = pos.y;
+
+ dbg("x=%d, y=%d\n",pos.x,pos.y);
+ vt1603_ts_report_pos(ts_drv, &pos);
+
+next_loop:
+ queue_delayed_work(ts_drv->workqueue, &ts_drv->read_work, 20*HZ/1000);
+
+ return;
+}
+
+
+static void vt1603_ts_work(struct work_struct *work)
+{
+ int int_sts;
+ //unsigned long flags;
+ struct vt1603_ts_drvdata *ts_drv=pContext;
+
+ //spin_lock_irqsave(&ts_drv->spinlock, flags);
+ mutex_lock(&ts_drv->ts_mutex);
+ int_sts = vt1603_get_reg8(ts_drv, VT1603_INTS_REG);
+ dbg("+++++++ ts int status 0x%02x +++++++\n",int_sts);
+
+ if ((int_sts & BIT4) == 0 || (int_sts & BIT1) == BIT1){
+ if(ts_drv->pen_state == TS_PENUP_STATE){
+ vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x03);/* vt1603 gpio1 as logic high output */
+ ts_drv->pen_state = TS_PENDOWN_STATE;
+ ts_drv->ts_stamp = jiffies;
+ vt1603_setup_ts_mode(ts_drv);
+ dbg("============= pendown =============\n");
+ vt1603_pos_cleanup();
+ if(ts_drv->dual_enable)
+ vt1603_ts_dual_support(&ts_drv->dual_work.work);
+ else
+ vt1603_read_loop(&ts_drv->read_work.work);
+
+ vt1603_clr_ts_irq(ts_drv, int_sts&0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+
+ return;
+ }
+ }
+
+ vt1603_clr_ts_irq(ts_drv, int_sts&0x0f);
+ //spin_unlock_irqrestore(&ts_drv->spinlock, flags);
+ mutex_unlock(&ts_drv->ts_mutex);
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+
+ return ;
+}
+
+
+static irqreturn_t vt1603_ts_isr(int irq, void *dev_id)
+{
+ struct vt1603_ts_drvdata *ts_drv = dev_id;
+
+ if(!gpio_irqstatus(ts_drv->intgpio) ||
+ !is_gpio_irqenable(ts_drv->intgpio))
+ return IRQ_NONE;
+
+ wmt_gpio_ack_irq(ts_drv->intgpio);
+ wmt_gpio_mask_irq(ts_drv->intgpio);
+ schedule_work(&ts_drv->work);
+ dbg("@@@@@@@ touch irq @@@@@@@\n");
+
+ return IRQ_HANDLED;
+}
+
+static int vt1603_register_input(struct vt1603_ts_drvdata * ts_drv)
+{
+ if(strcmp(ts_drv->dev_id,"VT1609"))
+ ts_drv->input->name = "vt1603-touch";
+ else
+ ts_drv->input->name = "vt1609-touch";
+
+ ts_drv->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ ts_drv->input->propbit[0] = BIT_MASK(INPUT_PROP_DIRECT);
+
+#ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used){
+ int i;
+ for (i = 0; i < TOUCH_KEY_NUM; i++)
+ set_bit(key_codes[i], ts_drv->input->keybit);
+
+ ts_drv->input->keycode = key_codes;
+ ts_drv->input->keycodesize = sizeof(unsigned int);
+ ts_drv->input->keycodemax = TOUCH_KEY_NUM;
+ }
+#endif
+ if (ts_drv->lcd_exchg) {
+ input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_y, 0, 0);
+ input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_x, 0, 0);
+ } else {
+ input_set_abs_params(ts_drv->input, ABS_MT_POSITION_X, 0, ts_drv->resl_x, 0, 0);
+ input_set_abs_params(ts_drv->input, ABS_MT_POSITION_Y, 0, ts_drv->resl_y, 0, 0);
+ }
+
+ input_register_device(ts_drv->input);
+ return 0;
+}
+
+
+/*
+ * vt1603_ts_calibration - vt1603 self calibration routine
+ * @ts_drv: vt1603 driver data
+ */
+static void vt1603_ts_calibration(struct vt1603_ts_drvdata *ts_drv)
+{
+ unsigned char i, j, tmp;
+ unsigned char cal[5][8] = {{0}};
+ unsigned int cal_sum[8] = {0};
+ struct vt1603_ts_platform_data *ts_pdata;
+
+ dbg("Enter\n");
+ ts_pdata = ts_drv->pdata;
+ for (j = 0; j < 5; j++) {
+ tmp = BIT6 | BIT0 | (ts_pdata->cal_sel << 4);
+ vt1603_set_reg8(ts_drv, VT1603_CCCR_REG, tmp);
+ msleep(100);
+ for (i = 0; i < 8; i++)
+ cal[j][i] = vt1603_get_reg8(ts_drv, VT1603_ERR8_REG + i);
+ }
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 5; j++)
+ cal_sum[i] += cal[j][i];
+ tmp = (u8)cal_sum[i]/5;
+ vt1603_set_reg8(ts_drv, VT1603_DBG8_REG + i, tmp);
+ }
+
+ dbg("Exit\n");
+ return ;
+}
+
+/*
+ * vt1603_ts_reset - reset vt1603, auto postition conversion mode,
+ * do self calibration if enable
+ * @ts_drv: vt1603 driver data
+ */
+static void vt1603_ts_reset(struct vt1603_ts_drvdata * ts_drv)
+{
+ struct vt1603_ts_platform_data *ts_pdata;
+ ts_pdata = ts_drv->pdata;
+
+ /* power control enable */
+ vt1603_set_reg8(ts_drv, VT1603_PWC_REG, 0x18);
+ /* begin calibrate if calibration enable */
+ if ((ts_pdata != NULL) && (ts_pdata->cal_en == CALIBRATION_ENABLE)) {
+ vt1603_ts_calibration(ts_drv);
+ }
+
+ /* clock divider */
+ vt1603_set_reg8(ts_drv, VT1603_CDPR_REG, ts_pdata->sclk_div);
+
+ /* clean debug register,for some 2 layer PCB machine enter debug mode unexpected */
+ vt1603_set_reg8(ts_drv, VT1603_DCR_REG, 0x00);
+
+ vt1603_set_reg8(ts_drv, VT1603_INTEN_REG, BIT1);//Just Enable pendown IRQ
+
+ /* auto position conversion mode and panel type config */
+ if (ts_pdata->panel_type== PANEL_TYPE_4WIRED)
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1);
+ else
+ vt1603_set_reg8(ts_drv, VT1603_CR_REG, BIT1 | BIT0);
+
+ /* interrupt control, pen up/down detection enable */
+ vt1603_set_reg8(ts_drv, VT1603_INTCR_REG, 0xff);
+
+ /* mask other module interrupts */
+ vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xff);
+ vt1603_set_reg8(ts_drv, VT1603_IMASK_REG28, 0xFF);
+ vt1603_set_reg8(ts_drv, VT1603_IMASK_REG29, 0xFF);
+ /* reset headphone detect irq */
+ vt1603_set_reg8(ts_drv, VT1603_IMASK_REG27, 0xfd);
+
+ if (ts_pdata->irq_type == HIGH_ACTIVE|| ts_pdata->irq_type == RISING_EDGE_ACTIVE)
+ vt1603_clrbits(ts_drv, VT1603_IPOL_REG33, BIT5);
+ else
+ vt1603_setbits(ts_drv, VT1603_IPOL_REG33, BIT5);
+
+ vt1603_set_reg8(ts_drv, VT1603_ISEL_REG36, 0x04);/* vt1603 gpio1 as IRQ output */
+ /* clear irq */
+ vt1603_clr_ts_irq(ts_drv, 0x0F);
+
+ return;
+}
+
+
+static struct vt1603_ts_platform_data vt1603_ts_pdata = {
+ .panel_type = PANEL_TYPE_4WIRED,
+ .cal_en = CALIBRATION_DISABLE,
+ .cal_sel = 0x00,
+ .shift = 0x00,
+ .sclk_div = 0x08,
+ .irq_type = LOW_ACTIVE,
+};
+
+struct delayed_work resume_work;
+static void vt1603_resume_work(struct work_struct* dwork)
+{
+ struct vt1603_ts_drvdata *ts_drv = pContext;
+ ts_drv->pen_state = TS_PENUP_STATE;
+
+ /* must ensure mclk is available */
+ vt1603_ts_clk_enable();
+ /* vt1603 ts hardware resume */
+ vt1603_ts_reset(ts_drv);
+ /* clear irq before enale gpio irq */
+ vt1603_clr_ts_irq(ts_drv, 0x0f );
+
+ gpio_direction_input(ts_drv->intgpio);
+ wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING);
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+ #ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ setup_led_gpio(ts_drv);
+#endif
+#ifdef VT1609_DEBUG
+ /* 4. dump vt1603 to ensure setting ok */
+ vt1603_reg_dump(ts_drv);
+#endif
+}
+static __devinit int
+vt1603_ts_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct vt1603_ts_drvdata *ts_drv = pContext;
+ struct vt1603_ts_platform_data *ts_pdata = NULL;
+
+ ts_pdata = &vt1603_ts_pdata;
+
+ ts_drv->pdata = ts_pdata;
+ ts_drv->pen_state = TS_PENUP_STATE;
+ ts_drv->tdev = dev_get_platdata(&pdev->dev);
+
+ //spin_lock_init(&ts_drv->spinlock);
+ mutex_init(&ts_drv->ts_mutex);
+
+ dev_set_drvdata(&pdev->dev, ts_drv);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ts_drv->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts_drv->earlysuspend.suspend = vt1603ts_early_suspend;
+ ts_drv->earlysuspend.resume = vt1603ts_late_resume;
+ register_early_suspend(&ts_drv->earlysuspend);
+#endif
+ /* 1. mclk enable */
+ vt1603_ts_clk_enable();
+ /* 2.vt1603 touch-panel and sar-adc module reset */
+ vt1603_ts_reset(ts_drv);
+
+#ifdef VT1609_DEBUG
+ /* 4. dump vt1603 to ensure setting ok */
+ vt1603_reg_dump(ts_drv);
+#endif
+ /* initial battery if battery detection enable */
+ /* initial temperature if temperature detection enable */
+
+ /* request iuput device */
+ ts_drv->input = input_allocate_device();
+ if (!ts_drv->input) {
+ printk("vt1603_ts: alloc input device failed");
+ ret = -ENOMEM;
+ goto release_driver_data;
+ }
+ vt1603_register_input(ts_drv);
+
+ INIT_DELAYED_WORK(&ts_drv->read_work, vt1603_read_loop);
+ INIT_DELAYED_WORK(&ts_drv->dual_work, vt1603_ts_dual_support);
+ INIT_DELAYED_WORK(&resume_work, vt1603_resume_work);
+ ts_drv->workqueue = create_singlethread_workqueue("vt160x-touch");
+ if(!ts_drv->workqueue){
+ printk("vt160x create singlethread work queue failed!\n");
+ goto release_driver_data;
+ }
+
+ INIT_WORK(&ts_drv->work, vt1603_ts_work);
+
+ if (request_irq(ts_drv->gpio_irq, vt1603_ts_isr, IRQF_SHARED, "vt160x-touch", ts_drv)) {
+ printk("vt160x_ts: request IRQ %d failed\n", ts_drv->gpio_irq);
+ ret = -ENODEV;
+ }
+
+ wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING);
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+
+#ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ setup_led_gpio(ts_drv);
+#endif
+
+ dbg("%s Touch Screen Driver Installed!\n",ts_drv->dev_id);
+ return ret;
+
+release_driver_data:
+ kfree(ts_drv);
+ ts_drv = NULL;
+
+ return ret;
+}
+
+static __devexit int
+vt1603_ts_remove(struct platform_device *pdev)
+{
+ struct vt1603_ts_drvdata *ts_drv;
+ ts_drv = dev_get_drvdata(&pdev->dev);
+
+ dbg("Enter\n");
+
+ wmt_gpio_mask_irq(ts_drv->intgpio);
+ if(ts_drv->dual_enable)
+ vt1603_dual_exit(ts_drv);
+
+ /* input unregister */
+ input_unregister_device(ts_drv->input);
+ cancel_work_sync(&ts_drv->work);
+ cancel_delayed_work_sync(&ts_drv->dual_work);
+ cancel_delayed_work_sync(&ts_drv->read_work);
+ destroy_workqueue(ts_drv->workqueue);
+ vt1603_ts_dev_cleanup(ts_drv);
+#ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ del_timer_sync(&ts_drv->led_timer);
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&ts_drv->earlysuspend);
+#endif
+ /* free vt1603 driver data */
+ dev_set_drvdata(&pdev->dev, NULL);
+ mutex_destroy(&ts_drv->ts_mutex);
+ free_irq(ts_drv->gpio_irq,ts_drv);
+ kfree(ts_drv);
+ ts_drv = NULL;
+
+ dbg("Exit\n");
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+
+static void
+vt1603ts_early_suspend(struct early_suspend *h)
+{
+ struct vt1603_ts_drvdata *ts_drv = pContext;
+
+ dbg("Enter\n");
+
+ wmt_gpio_mask_irq(ts_drv->intgpio);
+#ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){
+ del_timer_sync(&ts_drv->led_timer);
+ set_key_led_gpio(ts_drv,LOW);
+ }
+#endif
+
+ ts_drv->earlysus = 1;
+ dbg("Exit\n");
+ return;
+}
+
+static void
+vt1603ts_late_resume(struct early_suspend *h)
+{
+ struct vt1603_ts_drvdata *ts_drv = pContext;
+
+ dbg("Enter\n");
+ ts_drv->pen_state = TS_PENUP_STATE;
+
+ /* must ensure mclk is available */
+ vt1603_ts_clk_enable();
+ /* vt1603 ts hardware resume */
+ vt1603_ts_reset(ts_drv);
+ /* clear irq before enale gpio irq */
+ vt1603_clr_ts_irq(ts_drv, 0x0f );
+
+ ts_drv->earlysus = 0;
+ //wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING);
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+ #ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ setup_led_gpio(ts_drv);
+ dbg("Exit\n");
+#endif
+
+ return;
+}
+
+#endif
+
+static int
+vt1603_ts_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev);
+
+ dbg("Enter\n");
+#ifdef VT1609_DEBUG
+ /* 4. dump vt1603 to ensure setting ok */
+ vt1603_reg_dump(ts_drv);
+#endif
+
+ ts_drv = dev_get_drvdata(&pdev->dev);
+
+ wmt_gpio_mask_irq(ts_drv->intgpio);
+#ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0){
+ set_key_led_gpio(ts_drv,LOW);
+ del_timer_sync(&ts_drv->led_timer);
+ }
+#endif
+
+ dbg("Exit\n");
+ return 0;
+}
+
+static int
+vt1603_ts_resume(struct platform_device *pdev)
+{
+ //struct vt1603_ts_drvdata *ts_drv = dev_get_drvdata(&pdev->dev);
+
+ dbg("Enter\n");
+ //delay resume work because some resources were closed by audio driver.
+ schedule_delayed_work(&resume_work, HZ);
+#if 0
+ ts_drv->pen_state = TS_PENUP_STATE;
+
+ /* must ensure mclk is available */
+ vt1603_ts_clk_enable();
+ /* vt1603 ts hardware resume */
+ vt1603_ts_reset(ts_drv);
+ /* clear irq before enale gpio irq */
+ vt1603_clr_ts_irq(ts_drv, 0x0f );
+
+ gpio_direction_input(ts_drv->intgpio);
+ wmt_gpio_set_irq_type(ts_drv->intgpio, IRQ_TYPE_EDGE_FALLING);
+ wmt_gpio_unmask_irq(ts_drv->intgpio);
+ #ifdef TOUCH_KEY
+ if(ts_drv->touch_key_used && ts_drv->ledgpio >= 0)
+ setup_led_gpio(ts_drv);
+#endif
+#ifdef VT1609_DEBUG
+ /* 4. dump vt1603 to ensure setting ok */
+ vt1603_reg_dump(ts_drv);
+#endif
+#endif
+ dbg("Exit\n");
+
+ return 0;
+}
+
+#else
+#define vt1603_ts_suspend NULL
+#define vt1603_ts_resume NULL
+#endif
+
+
+static struct platform_driver vt1603_driver = {
+ .driver = {
+ .name = VT1603_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = vt1603_ts_probe,
+ .remove = vt1603_ts_remove,
+ .suspend = vt1603_ts_suspend,
+ .resume = vt1603_ts_resume,
+};
+
+static int vt1603_ts_dev_open(struct inode *inode, struct file *filp)
+{
+ struct vt1603_ts_drvdata *ts_drv;
+
+ dbg("Enter\n");
+
+ ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev);
+ if (ts_drv == NULL) {
+ printk("can not get vt1603_ts driver data\n");
+ return -ENODATA;
+ }
+ filp->private_data = ts_drv;
+
+ dbg("Exit\n");
+ return 0;
+}
+
+static int vt1603_ts_dev_close(struct inode *inode, struct file *filp)
+{
+ struct vt1603_ts_drvdata *ts_drv;
+
+ dbg("Enter\n");
+
+ ts_drv = container_of(inode->i_cdev, struct vt1603_ts_drvdata , cdev);
+ if (ts_drv == NULL) {
+ printk("can not get vt1603_ts driver data\n");
+ return -ENODATA;
+ }
+
+ dbg("Exit\n");
+ return 0;
+}
+
+static long vt1603_ts_dev_ioctl(struct file *filp,unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ int nBuff[7] = { 0 };
+ char env_val[96] = { 0 };
+ struct vt1603_ts_drvdata *ts_drv;
+
+ dbg("Enter\n");
+ /* check type and command number */
+ if (_IOC_TYPE(cmd) != VT1603_TS_IOC_MAGIC)
+ return -ENOTTY;
+
+ ts_drv = filp->private_data;
+ switch (cmd) {
+ case VT1603_TS_IOC_CAL_DONE:
+ copy_from_user(nBuff, (unsigned int *)arg, 7 * sizeof(int));
+ g_CalcParam.a1 = nBuff[0];
+ g_CalcParam.b1 = nBuff[1];
+ g_CalcParam.c1 = nBuff[2];
+ g_CalcParam.a2 = nBuff[3];
+ g_CalcParam.b2 = nBuff[4];
+ g_CalcParam.c2 = nBuff[5];
+ g_CalcParam.delta = nBuff[6];
+
+ if (g_CalcParam.delta == 0)
+ g_CalcParam.delta = 1;
+
+ sprintf(env_val, "%d %d %d %d %d %d %d",
+ nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]);
+
+ wmt_setsyspara("wmt.io.ts.2dcal", env_val);
+ printk("TOUCH CAL DONE: [%s]\n", env_val);
+ break;
+
+ case VT1603_TS_IOC_CAL_RAWDATA:
+ nBuff[0] = ts_drv->raw_x;
+ nBuff[1] = ts_drv->raw_y;
+ copy_to_user((unsigned int *)arg, nBuff, 2 * sizeof(int));
+ printk("TOUCH CAL RAWDATA: x=%-4d, y=%-4d \n", nBuff[0], nBuff[1]);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ dbg("Exit\n");
+ return ret;
+}
+
+static struct file_operations vt1603_ts_fops = {
+ .owner = THIS_MODULE,
+ .open = vt1603_ts_dev_open,
+ .unlocked_ioctl = vt1603_ts_dev_ioctl,
+ .release = vt1603_ts_dev_close,
+};
+
+
+static int vt1603_ts_dev_setup(struct vt1603_ts_drvdata *ts_drv)
+{
+ dev_t dev_no = 0;
+ int ret = 0;
+ struct device *dev = NULL;
+
+ dbg("Enter\n");
+ if (VT1603_TS_DEV_MAJOR) {
+ ts_drv->major = VT1603_TS_DEV_MAJOR;
+ ts_drv->minor = 0;
+ dev_no = MKDEV(ts_drv->major, ts_drv->minor);
+ ret = register_chrdev_region(dev_no, VT1603_TS_NR_DEVS, DEV_NAME);
+ } else {
+ ret = alloc_chrdev_region(&dev_no, 0, VT1603_TS_NR_DEVS, DEV_NAME);
+ ts_drv->major = MAJOR(dev_no);
+ ts_drv->minor = MINOR(dev_no);
+ dbg("vt1603_ts device major = %d, minor = %d \n", ts_drv->major,ts_drv->minor);
+ }
+
+ if (ret < 0) {
+ printk("can not get major %d\n", ts_drv->major);
+ goto out;
+ }
+
+ cdev_init(&ts_drv->cdev, &vt1603_ts_fops);
+
+ ts_drv->cdev.owner = THIS_MODULE;
+ ts_drv->cdev.ops = &vt1603_ts_fops;
+ ret = cdev_add(&ts_drv->cdev, dev_no, VT1603_TS_NR_DEVS);
+ if (ret) {
+ printk("add char dev for vt1603 ts failed\n");
+ goto release_region;
+ }
+
+ vt1603_ts_class = class_create(THIS_MODULE, ts_drv->dev_id);
+ if (IS_ERR(vt1603_ts_class)) {
+ printk("create vt1603_ts class failed\n");
+ ret = PTR_ERR(vt1603_ts_class);
+ goto release_cdev;
+ }
+
+ dev = device_create(vt1603_ts_class, NULL, dev_no, NULL, DEV_NAME);
+ if (IS_ERR(dev)) {
+ printk("create device for vt160x ts failed\n");
+ ret = PTR_ERR(dev);
+ goto release_class;
+ }
+
+ dbg("Exit\n");
+ return ret;
+
+release_class:
+ class_destroy(vt1603_ts_class);
+ vt1603_ts_class = NULL;
+release_cdev:
+ cdev_del(&ts_drv->cdev);
+release_region:
+ unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS);
+out:
+ return ret;
+}
+
+static void vt1603_ts_dev_cleanup(struct vt1603_ts_drvdata *ts_drv)
+{
+ dev_t dev_no = MKDEV(ts_drv->major, ts_drv->minor);
+
+ dbg("Enter\n");
+ cdev_del(&ts_drv->cdev);
+ unregister_chrdev_region(dev_no, VT1603_TS_NR_DEVS);
+ device_destroy(vt1603_ts_class, dev_no);
+ class_destroy(vt1603_ts_class);
+ dbg("Exit\n");
+}
+
+#ifdef TOUCH_KEY
+static int parse_touch_key_env(struct vt1603_ts_drvdata *ts_drv)
+{
+ int i = 0;
+ int ret = 0;
+ int len = 96;
+ char retval[96] = {0};
+ char *p = NULL;
+
+ ret = wmt_getsyspara("wmt.ts.vkey", retval, &len);
+ if(ret){
+ printk("Read wmt.ts.vkey Failed.\n");
+ return -EIO;
+ }
+
+ sscanf(retval,"%d:%d:%d:%d", &ts_drv->tsc_key.key_num,
+ &ts_drv->tsc_key.low, &ts_drv->tsc_key.upper, &ts_drv->tsc_key.delta);
+
+ if(!ts_drv->tsc_key.key_num){
+ printk("tsc key number is zero!\n");
+ return -EIO;
+ }
+
+ p = retval;
+ i = 4;
+ while(i--){
+ p = strchr(p,':');
+ p++;
+ }
+
+ for(i = 0; i < ts_drv->tsc_key.key_num; i++){
+ sscanf(p,"%d_%d",&ts_drv->tsc_key.key[i].pos,&ts_drv->tsc_key.key[i].idx );
+ p = strchr(p,':');
+ p++;
+ }
+
+ dbg("%d:%d:%d:%d:%d_%d:%d_%d:%d_%d:%d_%d\n",
+ ts_drv->tsc_key.key_num,
+ ts_drv->tsc_key.low,
+ ts_drv->tsc_key.upper,
+ ts_drv->tsc_key.delta,
+ ts_drv->tsc_key.key[0].pos,
+ ts_drv->tsc_key.key[0].idx,
+ ts_drv->tsc_key.key[1].pos,
+ ts_drv->tsc_key.key[1].idx,
+ ts_drv->tsc_key.key[2].pos,
+ ts_drv->tsc_key.key[2].idx,
+ ts_drv->tsc_key.key[3].pos,
+ ts_drv->tsc_key.key[3].idx);
+
+ return 0;
+
+}
+#endif
+
+static int parse_dual_env(struct vt1603_ts_drvdata *ts_drv)
+{
+ int ret = 0;
+ int len = 96;
+ char retval[96] = {0};
+
+ len = sizeof(retval);
+ ret = wmt_getsyspara("wmt.io.vt1609", retval, &len);
+ if(ret){
+ //printk("wmt.io.vt1609 not set, use default parameter.\n");
+ ts_drv->dual_dev.vxy = 17;
+ ts_drv->dual_dev.scale_x = 4;
+ ts_drv->dual_dev.scale_y = 2;
+ ts_drv->dual_dev.F1_CNT = 2;
+ ts_drv->dual_dev.F2_CNT = 7;
+ ts_drv->dual_dev.F2T1_CNT = 15;
+ ts_drv->dual_dev.SAMPLE_CNT = 1;
+ ts_drv->dual_dev.THR_MIN_DX = 13;
+ ts_drv->dual_dev.THR_MAX_DX = 256;
+ ts_drv->dual_dev.exch = 0;
+
+ return 0;
+ }
+
+ sscanf(retval,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &ts_drv->dual_dev.vxy,
+ &ts_drv->dual_dev.scale_x,
+ &ts_drv->dual_dev.scale_y,
+ &ts_drv->dual_dev.F1_CNT,
+ &ts_drv->dual_dev.F2_CNT,
+ &ts_drv->dual_dev.F2T1_CNT,
+ &ts_drv->dual_dev.SAMPLE_CNT,
+ &ts_drv->dual_dev.THR_MIN_DX,
+ &ts_drv->dual_dev.THR_MAX_DX,
+ &ts_drv->dual_dev.exch);
+ /*
+ printk("%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ ts_drv->dual_dev.vxy,
+ ts_drv->dual_dev.scale_x,
+ ts_drv->dual_dev.scale_y,
+ ts_drv->dual_dev.F1_CNT,
+ ts_drv->dual_dev.F2_CNT ,
+ ts_drv->dual_dev.F2T1_CNT ,
+ ts_drv->dual_dev.SAMPLE_CNT ,
+ ts_drv->dual_dev.THR_MIN_DX ,
+ ts_drv->dual_dev.THR_MAX_DX),
+ ts_drv->dual_dev.exch;
+ */
+ return 0;
+}
+
+static int vt1603_uboot_env_check(struct vt1603_ts_drvdata *ts_drv)
+{
+ int nBuff[7] = {0};
+ int i = 0, Enable = 0;
+ int intgpio=0;
+ int ledgpio=-1;
+ int reslx=480,resly=800;
+ int ret=0,len = 96;
+ char retval[96] = {0};
+ char *p=NULL;
+
+ // Get u-boot parameter
+ ret = wmt_getsyspara("wmt.io.touch", retval, &len);
+ if(ret){
+ printk("Read wmt.io.touch Failed.\n");
+ return -EIO;
+ }
+
+ sscanf(retval,"%d:",&Enable);
+ //check touch enable
+ if(Enable == 0){
+ printk("System touchscreen is disbaled.\n");
+ return -ENODEV;
+ }
+
+ p = strchr(retval,':');
+ p++;
+ if(strncmp(p,"vt1603",6) == 0){//check touch ID
+ strcpy(ts_drv->dev_id, "VT1603A");
+ }
+ else if(strncmp(p,"vt1609",6) == 0){//check touch ID
+ ts_drv->dual_enable = 1;
+ strcpy(ts_drv->dev_id, "VT1609");
+ parse_dual_env(ts_drv);
+ }
+ else{
+ printk("Vt1609 touchscreen driver disabled.\n");
+ return -ENODEV;
+ }
+
+ p = strchr(p,':');
+ p++;
+ sscanf(p,"%d:%d:%d:%d",&reslx, &resly, &intgpio, &ledgpio);
+
+ ts_drv->resl_x = reslx;
+ ts_drv->resl_y = resly;
+
+ ts_drv->intgpio = intgpio;
+
+ ts_drv->ledgpio = ledgpio;
+
+ ts_drv->gpio_irq = IRQ_GPIO;
+
+ printk("%s-Touch: reslx=%d resly=%d, Interrupt GPIO%d , Virtual Touch Key Led GPIO%d\n",ts_drv->dev_id,
+ ts_drv->resl_x, ts_drv->resl_y, ts_drv->intgpio, ts_drv->ledgpio);
+
+ len = sizeof(retval);
+ memset(retval, 0, sizeof(retval));
+
+ ret = wmt_getsyspara("wmt.io.ts.2dcal", retval, &len);
+ if(ret){
+ printk("Read env wmt.io.ts.2dcal Failed.\n");
+ //return -EIO;
+ }
+
+ for (i = 0; i < sizeof(retval); i++) {
+ if (retval[i] == ' ' || retval[i] == ',' || retval[i] == ':')
+ retval[i] = '\0';
+ }
+
+ p = retval;
+ for (i = 0; (i < 7) && (p < (retval + sizeof(retval))); ) {
+ if (*p == '\0')
+ p++;
+ else {
+ sscanf(p, "%d", &nBuff[i]);
+ p = p + strlen(p);
+ i++;
+ }
+ }
+ dbg("Touchscreen Calibrate Data: [%d %d %d %d %d %d %d]\n",
+ nBuff[0], nBuff[1], nBuff[2], nBuff[3], nBuff[4], nBuff[5], nBuff[6]);
+
+ g_CalcParam.a1 = nBuff[0];
+ g_CalcParam.b1 = nBuff[1];
+ g_CalcParam.c1 = nBuff[2];
+ g_CalcParam.a2 = nBuff[3];
+ g_CalcParam.b2 = nBuff[4];
+ g_CalcParam.c2 = nBuff[5];
+ g_CalcParam.delta = nBuff[6];
+
+ if(g_CalcParam.delta == 0)
+ g_CalcParam.delta = 1;
+
+ memset(retval,0,sizeof(retval));
+ ret = wmt_getsyspara("wmt.display.fb0", retval, &len);
+ if (!ret) {
+ int tmp[6];
+ p = retval;
+ sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
+ if (tmp[4] > tmp[5])
+ ts_drv->lcd_exchg = 1;
+ }
+
+ return 0;
+}
+
+static int gpio_resource_request(void)
+{
+ if (gpio_request(pContext->intgpio, "ts_irq") < 0) {
+ printk("gpio(%d) touchscreen interrupt request fail\n", pContext->intgpio);
+ return -EIO;
+ }
+ gpio_direction_input(pContext->intgpio);
+
+ if (pContext->ledgpio >= 0) {
+ if (gpio_request(pContext->ledgpio, "ts_led") < 0) {
+ printk("gpio(%d) touchscreen led gpio request fail\n", pContext->ledgpio);
+ gpio_free(pContext->intgpio);
+ return -EIO;
+ }
+ gpio_direction_output(pContext->ledgpio, 0);
+ }
+
+ return 0;
+}
+static void gpio_resource_free(void)
+{
+ gpio_free(pContext->intgpio);
+ if (pContext->ledgpio >= 0)
+ gpio_free(pContext->ledgpio);
+}
+
+
+static int __init vt1603_ts_init(void)
+{
+ int ret = 0;
+ struct vt1603_ts_drvdata *ts_drv = NULL;
+
+ dbg("Enter\n");
+ ts_drv = kzalloc(sizeof(struct vt1603_ts_drvdata), GFP_KERNEL);
+ if (!ts_drv) {
+ printk("vt160x ts: alloc driver data failed\n");
+ return -ENOMEM;
+ }
+ pContext = ts_drv;
+ ret = vt1603_uboot_env_check(ts_drv);
+ if (ret) {//vt1603 touch disabled
+ goto out;
+ }else{//vt1603 touch enabled
+ if (gpio_resource_request())
+ goto out;
+ ret = vt1603_ts_dev_setup(ts_drv);//only touch calibrate need dev node
+ if (ret) {
+ printk("##ERR## vt160x ts create device node failed.\n");
+ goto freegpio;
+ }
+
+#ifdef TOUCH_KEY
+ if(!parse_touch_key_env(ts_drv)){
+ ts_drv->touch_key_used = 1;
+ if(ts_drv->ledgpio >= 0){//touch virtual key back light led enabled
+ init_timer(&ts_drv->led_timer);
+ ts_drv->led_timer.function = led_timer_func;
+ ts_drv->led_timer.data = (unsigned long) ts_drv;
+ }
+ }
+#endif
+ }
+
+ ret = platform_driver_register(&vt1603_driver);
+ if(ret){
+ printk("vt160x platform driver register failed!.\n");
+ goto release_dev;
+ }
+
+ if(ts_drv->dual_enable)
+ vt1603_dual_init(ts_drv);
+
+ dbg("Exit\n");
+ return ret;
+
+release_dev:
+ vt1603_ts_dev_cleanup(ts_drv);
+freegpio:
+ gpio_resource_free();
+out:
+ kfree(ts_drv);
+
+ return ret;
+}
+//module_init(vt1603_ts_init);
+late_initcall(vt1603_ts_init);
+static void __exit vt1603_ts_exit(void)
+{
+ dbg("Enter\n");
+
+ platform_driver_unregister(&vt1603_driver);
+ gpio_resource_free();
+
+ dbg("Exit\n");
+}
+module_exit(vt1603_ts_exit);
+
+MODULE_DESCRIPTION("VT1603A/VT1609 TouchScreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h b/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h
new file mode 100755
index 00000000..31210579
--- /dev/null
+++ b/drivers/input/touchscreen/vt1609_ts/vt1609_ts.h
@@ -0,0 +1,301 @@
+#ifndef __VT1603_TS_H__
+#define __VT1603_TS_H__
+#include <linux/mfd/vt1603/core.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#define DEV_NAME "wmtts"
+#define VT1603_DRIVER_NAME "vt1603-touch"
+
+#undef abs
+#define abs(x) (((x)>0)?(x):(-(x)))
+
+#define FALSE 0
+#define TRUE 1
+#define VT1603_TS_NR_DEVS 1
+#define VT1603_TS_DEV_MAJOR 160
+#define TS_DEBOUNCE 50
+#define VT1603_FILTER_HEAD_COUNT 2
+#define VT1603_JITTER_THRESHOLD 1200//单点前后2点之间的x/y 变化最大容许值
+
+#define None_TOUCH 0x00
+#define Single_TOUCH 0x01
+#define Multi_TOUCH 0x02
+
+#define ADC_DATA(low, high) ((((high) & 0x0F) << 8) + (low))
+
+/* touch panel type config */
+#define PANEL_TYPE_4WIRED 0x10
+#define PANEL_TYPE_5WIRED 0x11
+
+/* enable calibration or not */
+#define CALIBRATION_ENABLE 0x01
+#define CALIBRATION_DISABLE 0x00
+
+/* VT1603 working mode */
+#define VT1603_TS_MODE BIT1
+#define VT1603_TEMP_MODE BIT2
+#define VT1603_BAT_MODE BIT3
+
+/* VT1603 touch panel state */
+#define TS_PENDOWN_STATE 0x00
+#define TS_PENUP_STATE 0x01
+
+struct vt1603_ts_pos {
+ int x;
+ int y;
+};
+
+#define VT1603_FIFO_LEN 3
+struct vt1603_fifo{
+ int head;
+ int full;
+ int buf[VT1603_FIFO_LEN];
+};
+
+#define I2C_BUS 0x00
+#define SPI_BUS 0x01
+
+#define VT1603_SPI_FIX_CS 0x00
+#define VT1603_SPI_FAKE_CS 0x03
+#define VT1603_SPI_BUS_0 0x00
+#define VT1603_SPI_BUS_1 0x01
+#define VT1603_MAX_SPI_CLK (20*1000*1000)
+#define SPI_DEFAULT_CLK (4*1000*1000)
+#define IDLE_DATA_NUM 5
+
+#define VT1603_I2C_FIX_ADDR 0x1A
+#define VT1603_I2C_FAKE_ADDR 0xFF
+#define VT1603_TS_I2C_WCMD 0x00
+#define VT1603_TS_I2C_RCMD 0x01
+#define VT1603_TS_I2C_RWCMD 0x02
+#define VT1603_I2C_BUS_0 0x00
+#define VT1603_I2C_BUS_1 0x01
+
+///////////////////////////////
+//#define TOUCH_KEY
+#define KEY_DETLA 300
+#define TOUCH_KEY_NUM 4
+#define TOUCH_KEY_LED_GPIO 4
+
+#define HIGH 1
+#define LOW 0
+
+struct tsc_key{
+ int pos;
+ int idx;
+};
+
+struct tsc_key_st{
+ int key_num;
+ int low;
+ int upper;
+ int delta;
+ struct tsc_key key[TOUCH_KEY_NUM];
+};
+
+enum key_idx{
+ _SEARCH,
+ _BACK,
+ _HOME,
+ _MENU,
+ _MAX_NUM,
+};
+/////////////////////////
+
+enum gpio_irq_type {
+ HIGH_ACTIVE = 0,
+ LOW_ACTIVE = 1,
+ RISING_EDGE_ACTIVE = 3,
+ FALLING_EDGE_ACTIVE = 4,
+ UNKOWN_TYPE = 0xFF
+};
+
+/*
+ * vt1603_ts_platform_data - vt1603 configuration data
+ * @panel_type: touch panel type: 4-wired or 5-wired
+ * @cal_en: enable calibration circuit or not
+ * @cal_sel: calibratin capacitor control bits
+ * @shfit: conversion data shfit
+ * @sclk_div: initial value of sclk dividor if mclk = 12.288MHZ 0x04 = 200ksps 0x08 = 100ksps
+ * @soc_gpio_irq: soc gpio interrupts, connect with vt1603 gpio1
+ */
+struct vt1603_ts_platform_data {
+ u8 panel_type;
+ u8 cal_en;
+ u8 cal_sel:2;
+ u8 shift;
+ u8 sclk_div;
+ int soc_gpio_irq;
+ int gpio_num;
+ enum gpio_irq_type irq_type;
+};
+
+struct vt1609_dual_st{
+ int vxy;
+
+ int scale_x;
+ int scale_y;
+
+ int F1_CNT;
+ int F2_CNT;
+ int F2T1_CNT;
+ int SAMPLE_CNT;
+
+ int THR_MIN_DX;
+ int THR_MAX_DX;
+
+ int exch;
+};
+
+struct vt1603_ts_drvdata {
+ struct vt1603 *tdev;
+ //spinlock_t spinlock;
+ struct mutex ts_mutex;
+ struct input_dev *input;
+ struct work_struct work;
+ struct delayed_work read_work;
+ struct delayed_work dual_work;
+ struct workqueue_struct *workqueue;
+ struct vt1603_ts_platform_data *pdata;
+
+ int earlysus;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend earlysuspend;
+#endif
+ char dev_id[32];
+
+ struct cdev cdev;
+ int major;
+ int minor;
+
+ int gpio_irq;
+
+ int intgpio;
+
+ u8 pen_state;
+ int ts_stamp;
+ int hcnt;
+
+ int resl_x;
+ int resl_y;
+ int lcd_exchg;
+
+ int raw_x;
+ int raw_y;
+
+ int dual_enable;
+ struct vt1609_dual_st dual_dev;
+
+ int ledgpio;
+#ifdef TOUCH_KEY
+ int key_idx;
+ int key_pressed;
+ int touch_key_used;
+ struct timer_list led_timer;
+ struct tsc_key_st tsc_key;
+#endif
+
+};
+
+/* VT1603 Register address */
+#define VT1603_BTHD_REG 0x78
+#define VT1603_BCLK_REG 0x88
+#define VT1603_BAEN_REG 0x04
+
+#define VT1603_PWC_REG 0xC0
+#define VT1603_CR_REG 0xC1
+#define VT1603_CCCR_REG 0xC2
+#define VT1603_CDPR_REG 0xC3
+#define VT1603_TSPC_REG 0xC4
+#define VT1603_AMCR_REG 0xC7
+#define VT1603_INTCR_REG 0xC8
+#define VT1603_INTEN_REG 0xC9
+#define VT1603_INTS_REG 0xCA
+#define VT1603_DCR_REG 0xCB
+
+#define VT1603_TODCL_REG 0xCC
+#define VT1603_TODCH_REG 0xCD
+
+#define VT1603_DATL_REG 0xCE
+#define VT1603_DATH_REG 0xCF
+
+#define VT1603_XPL_REG 0xD0
+#define VT1603_XPH_REG 0xD1
+#define VT1603_YPL_REG 0xD2
+#define VT1603_YPH_REG 0xD3
+
+#define VT1603_BATL_REG 0xD4
+#define VT1603_BATH_REG 0xD5
+
+#define VT1603_TEMPL_REG 0xD6
+#define VT1603_TEMPH_REG 0xD7
+
+#define VT1603_ERR8_REG 0xD8
+#define VT1603_ERR7_REG 0xD9
+#define VT1603_ERR6_REG 0xDA
+#define VT1603_ERR5_REG 0xDB
+#define VT1603_ERR4_REG 0xDC
+#define VT1603_ERR3_REG 0xDD
+#define VT1603_ERR2_REG 0xDE
+#define VT1603_ERR1_REG 0xDF
+
+#define VT1603_DBG8_REG 0xE0
+#define VT1603_DBG7_REG 0xE1
+#define VT1603_DBG6_REG 0xE2
+#define VT1603_DBG5_REG 0xE3
+#define VT1603_DBG4_REG 0xE4
+#define VT1603_DBG3_REG 0xE5
+#define VT1603_DBG2_REG 0xE6
+#define VT1603_DBG1_REG 0xE7
+
+/* for VT1603 GPIO1 interrupt setting */
+#define VT1603_IMASK_REG27 27
+#define VT1603_IMASK_REG28 28
+#define VT1603_IMASK_REG29 29
+#define VT1603_IPOL_REG33 33
+#define VT1603_ISEL_REG36 36
+
+struct vt1603_ts_cal_info {
+ int a1;
+ int b1;
+ int c1;
+ int a2;
+ int b2;
+ int c2;
+ int delta;
+};
+
+/* VT1603 TS and SAR-ADC IOCTL */
+#define VT1603_TS_IOC_MAGIC 't'
+
+/* for touch screen calibration */
+#define VT1603_TS_IOC_CAL_START _IO(VT1603_TS_IOC_MAGIC, 1)
+#define VT1603_TS_IOC_CAL_DONE _IOW(VT1603_TS_IOC_MAGIC, 2, int *)
+#define VT1603_TS_IOC_CAL_RAWDATA _IOR(VT1603_TS_IOC_MAGIC, 3, int *)
+#define VT1603_TS_IOC_CAL_QUIT _IOW(VT1603_TS_IOC_MAGIC, 4, int *)
+
+extern int wmt_setsyspara(char *varname, unsigned char *varval);
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlenex);
+
+int vt1603_clr_ts_irq(struct vt1603_ts_drvdata *ts_drv, u8 mask);
+int vt1603_set_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 val);
+u8 vt1603_get_reg8(struct vt1603_ts_drvdata *ts_drv, u8 reg);
+void vt1603_setbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask);
+void vt1603_clrbits(struct vt1603_ts_drvdata *ts_drv, u8 reg, u8 mask);
+
+void vt1603_ts_report_pos(struct vt1603_ts_drvdata *ts_drv, struct vt1603_ts_pos *pos);
+int vt1603_ts_pos_calibration(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos *to_cal);
+
+#ifdef TOUCH_KEY
+void vt1603_ts_report_key(struct vt1603_ts_drvdata *ts_drv);
+int vt1603_ts_get_key(struct vt1603_ts_drvdata *ts_drv,struct vt1603_ts_pos pos);
+int set_key_led_gpio(struct vt1603_ts_drvdata *ts_drv,int val);
+#endif
+
+int vt1603_dual_init(struct vt1603_ts_drvdata *ts_drv);
+void vt1603_dual_exit(struct vt1603_ts_drvdata *ts_drv);
+void vt1603_ts_dual_support(struct work_struct* work);
+
+#endif /* __VT1603_TS_H__ */