#include <linux/unistd.h> #include <linux/time.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> //#include <asm/semaphore.h> #include <linux/proc_fs.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/interrupt.h> #include <linux/suspend.h> #include <linux/proc_fs.h> #include <linux/input.h> #include <linux/types.h> #include <linux/platform_device.h> #include <mach/hardware.h> #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/irq.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/syscalls.h> #include "wmt_ts.h" #include "ssd253x-ts.h" ///////////////////////////////////////////////////////////////// // commands for ui #define TS_IOC_MAGIC 't' #define TS_IOCTL_CAL_START _IO(TS_IOC_MAGIC, 1) #define TS_IOCTL_CAL_DONE _IOW(TS_IOC_MAGIC, 2, int*) #define TS_IOCTL_GET_RAWDATA _IOR(TS_IOC_MAGIC, 3, int*) #define TS_IOCTL_CAL_QUIT _IOW(TS_IOC_MAGIC, 4, int*) #define TS_IOCTL_AUTO_CALIBRATION _IOW(TS_IOC_MAGIC, 5, int*) #define TS_IOC_MAXNR 5 // #define TS_MAJOR 11 #define TS_DRIVER_NAME "wmtts_touch" #define TS_NAME "wmtts" #define WMTTS_PROC_NAME "wmtts_config" #define EXT_GPIO0 0 #define EXT_GPIO1 1 #define EXT_GPIO2 2 #define EXT_GPIO3 3 #define EXT_GPIO4 4 #define EXT_GPIO5 5 #define EXT_GPIO6 6 #define EXT_GPIO7 7 typedef struct { int a1; int b1; int c1; int a2; int b2; int c2; int delta; }CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER; static int lcd_exchg = 0; static int irq_gpio; static int rst_gpio; static int panelres_x; static int panelres_y; static int l_xaxis=0; static int l_xdirect=1; static int l_yaxis=1; static int l_ydirect=1; static int l_cutedge=-1; static DECLARE_WAIT_QUEUE_HEAD(queue); static CALIBRATION_PARAMETER g_CalcParam; static TS_EVENT g_evLast; static struct mutex cal_mutex; static DECLARE_WAIT_QUEUE_HEAD(ts_penup_wait_queue); extern struct wmtts_device raysen_tsdev; static struct wmtts_device* l_tsdev = &raysen_tsdev; static struct i2c_client *l_client=NULL; static int l_penup = 0; // 1-pen up,0-pen down static char l_firmid[21]; ///////////////////////////////////////////////////// // function declare ///////////////////////////////////////////////////// extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); extern int wmt_setsyspara(char *varname, unsigned char *varval); /////////////////////////////////////////////////////////////////////// void TouchPanelCalibrateAPoint( int UncalX, //@PARM The uncalibrated X coordinate int UncalY, //@PARM The uncalibrated Y coordinate int *pCalX, //@PARM The calibrated X coordinate int *pCalY //@PARM The calibrated Y coordinate ) { int x, y; mutex_lock(&cal_mutex); x = (g_CalcParam.a1 * UncalX + g_CalcParam.b1 * UncalY + g_CalcParam.c1) / g_CalcParam.delta; y = (g_CalcParam.a2 * UncalX + g_CalcParam.b2 * UncalY + g_CalcParam.c2) / g_CalcParam.delta; //klog("afer(%d,%d)(%d,%d)\n", x,y,panelres_x,panelres_y); if ( x < 0 ) x = 0; if ( y < 0 ) y = 0; if (x >= panelres_x) x = panelres_x-1; if (y >= panelres_y) y = panelres_y-1; *pCalX = x; *pCalY = y; mutex_unlock(&cal_mutex); return; } static int parse_firmwarefile(const char* filedata, struct ChipSetting** firmarr, int maxlen) { char endflag[]="/* End flag */"; const char* p = filedata; int val[4]; int i = 0; int j = 0; const char* s = NULL; // the first { while (*p!='{') p++; p++; s = p; // calculate the number of array while (strncmp(p,endflag,strlen(endflag))) { if (*p=='{') { i++; } p++; }; dbg("the number of arry:0x%x\n", i); // alloc the memory for array *firmarr = kzalloc(sizeof(struct ChipSetting)*i, GFP_KERNEL); // parse the value of array p = s; j = 0; while (strncmp(p,endflag,strlen(endflag))) { if (*p=='{') { memset(val,0,sizeof(val)); sscanf(p,"{%x,%x,%x,%x}",val,val+1,val+2,val+3); (*firmarr)[j].No = val[0]&0x00FF; (*firmarr)[j].Reg = val[1]&0x00FF; (*firmarr)[j].Data1 = val[2]&0x00FF; (*firmarr)[j].Data2 = val[3]&0x00FF; dbg("arry[0x%x]:%x,%x,%x,%x\n",j,(*firmarr)[j].No,(*firmarr)[j].Reg,(*firmarr)[j].Data1, (*firmarr)[j].Data2); j++; } //p = strchr(p,'}'); p++; if (j>=i-2) { dbg("%s",p); } }; if (i != j) { errlog("Error parsing file(the number of arry not match)!\n"); return -1; }; dbg("paring firmware file end.\n"); return i; } static struct device* get_tp_device(void){ if(l_client == NULL){ errlog("l_client is NULL\n"); } return &l_client->dev; } //filepath:the path of firmware file; //firmdata:store the data from firmware file; //maxlen: the max len of firmdata; //return:the number of firmware data,negative-parsing error. int read_firmwarefile(char* filepath, struct ChipSetting** firmdata, int maxlen) { const u8 *data = NULL; int i = 0; int ret = -1; const struct firmware* tpfirmware = NULL; klog("ts config file:%s\n",filepath); ret = request_firmware(&tpfirmware, filepath, get_tp_device()); if (ret < 0) { errlog("Failed load tp firmware: %s ret=%d\n", filepath,ret); goto err_end; } data = tpfirmware->data; i = parse_firmwarefile(data,firmdata,maxlen); if (i <= 0) { errlog("error to parse firmware file.\n"); ret = -1; goto error_parse_fw; } ret = i; dbg("success to read firmware file!\n");; error_parse_fw: if(tpfirmware){ release_firmware(tpfirmware); tpfirmware = NULL; } err_end: return ret; } int wmt_ts_get_gpionum(void) { return irq_gpio; } int wmt_ts_get_resetgpnum(void) { return rst_gpio; } int wmt_ts_get_lcdexchg(void) { return lcd_exchg; } int wmt_ts_get_resolvX(void) { return panelres_x; } int wmt_ts_get_resolvY(void) { return panelres_y; } int wmt_ts_get_xaxis(void) { return l_xaxis; } int wmt_ts_get_xdir(void) { return l_xdirect; } int wmt_ts_get_yaxis(void) { return l_yaxis; } int wmt_ts_get_ydir(void) { return l_ydirect; } int wmt_ts_get_cutedge(void) { return l_cutedge; } void wmt_ts_get_firmwname(char* firmname) { sprintf(firmname,"ssd253x_%s_cfg.tpf",l_firmid); } int wmt_ts_get_fingernum(void) { if (!strcmp(l_firmid,"10rs10f1609043psy1")) { return 10; } return 5; } //up:1-pen up,0-pen down void wmt_ts_set_penup(int up) { l_penup = up; } // int wmt_ts_wait_penup(void) { int ret = wait_event_interruptible( ts_penup_wait_queue, (1==l_penup)); return ret; } // return:1-pen up,0-pen dwon int wmt_ts_ispenup(void) { return l_penup; } void wmt_ts_wakeup_penup(void) { wake_up(&ts_penup_wait_queue); } int wmt_is_tsirq_enable(void) { int val = 0; int num = irq_gpio; if(num > 11) return 0; if(num<4) val = REG32_VAL(__GPIO_BASE+0x0300) & (1<<(num*8+7)); else if(num >= 4 && num < 8) val = REG32_VAL(__GPIO_BASE+0x0304) & (1<<((num-4)*8+7)); else val = REG32_VAL(__GPIO_BASE+0x0308) & (1<<((num-8)*8+7)); return val?1:0; } int wmt_is_tsint(void) { int num = irq_gpio; if (num > 11) { return 0; } return (REG32_VAL(__GPIO_BASE+0x0360) & (1<<num)) ? 1: 0; } void wmt_clr_int(void) { int num = irq_gpio; if (num > 11) { return; } REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; } void wmt_tsreset_init(void) { int num = rst_gpio; REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num);//&= ~(1<<num); //enable gpio REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<num); // out low REG32_VAL(__GPIO_BASE+0x0080) |= (1<<num); //output enable msleep(10); REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<num); // out high } // enable:0-disable,1-enable void wmt_enable_rst_pull(int enable) { if (enable) { REG32_VAL(__GPIO_BASE+0x0480) |= (1<<rst_gpio); //enable pull up/down } else { REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<rst_gpio); //disable pull up/down } } // up:0-pull down,1-pull up void wmt_set_rst_pull(int up) { if (up) { REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<rst_gpio); //pull up } else { REG32_VAL(__GPIO_BASE+0x04c0) &= ~(1<<rst_gpio); //pull down } } // high:0-low level,1-high level void wmt_rst_output(int high) { REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio if (high) { REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<rst_gpio); // high } else { REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<rst_gpio); // low } REG32_VAL(__GPIO_BASE+0x0080) |= (1<<rst_gpio); //set output } void wmt_rst_input(void) { REG32_VAL(__GPIO_BASE+0x0040) |= (1<<rst_gpio); //enable gpio REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<rst_gpio); //set input } void wmt_set_intasgp(void) { REG32_VAL(__GPIO_BASE+0x0040) |= (1<<irq_gpio); //enable gpio } // val:1--high,0-low void wmt_intgp_out(int val) { if (val) { REG32_VAL(__GPIO_BASE+0x00C0) |= (1<<irq_gpio); // high } else { REG32_VAL(__GPIO_BASE+0x00C0) &= ~(1<<irq_gpio); // low } REG32_VAL(__GPIO_BASE+0x0080) |= (1<<irq_gpio); //set output } void wmt_ts_set_irqinput(void) { int num = irq_gpio; REG32_VAL(__GPIO_BASE+0x0040) |= (1<<num); //enable gpio REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input } unsigned int wmt_ts_irqinval(void) { return REG32_VAL(__GPIO_BASE+0x0000)&(1<<irq_gpio); } int wmt_set_gpirq(int type) { int shift; int offset; unsigned long reg; int num = irq_gpio; if(num >11) return -1; //if (num > 9) //GPIO_PIN_SHARING_SEL_4BYTE_VAL &= ~BIT4; // gpio10,11 as gpio REG32_VAL(__GPIO_BASE+0x0040) &= ~(1<<num); //enable gpio REG32_VAL(__GPIO_BASE+0x0080) &= ~(1<<num); //set input REG32_VAL(__GPIO_BASE+0x04c0) |= (1<<num); //pull down REG32_VAL(__GPIO_BASE+0x0480) &= ~(1<<num); //enable pull up/down //set gpio irq triger type if(num < 4){//[0,3] shift = num; offset = 0x0300; }else if(num >= 4 && num < 8){//[4,7] shift = num-4; offset = 0x0304; }else{// [8,11] shift = num-8; offset = 0x0308; } reg = REG32_VAL(__GPIO_BASE + offset); switch(type){ case IRQ_TYPE_LEVEL_LOW: reg &= ~(1<<(shift*8+2)); reg &= ~(1<<(shift*8+1)); reg &= ~(1<<(shift*8)); break; case IRQ_TYPE_LEVEL_HIGH: reg &= ~(1<<(shift*8+2)); reg &= ~(1<<(shift*8+1)); reg |= (1<<(shift*8)); break; case IRQ_TYPE_EDGE_FALLING: reg &= ~(1<<(shift*8+2)); reg |= (1<<(shift*8+1)); reg &= ~(1<<(shift*8)); break; case IRQ_TYPE_EDGE_RISING: reg &= ~(1<<(shift*8+2)); reg |= (1<<(shift*8+1)); reg |= (1<<(shift*8)); break; default://both edge reg |= (1<<(shift*8+2)); reg &= ~(1<<(shift*8+1)); reg &= ~(1<<(shift*8)); break; } //reg |= 1<<(shift*8+7);//enable interrupt reg &= ~(1<<(shift*8+7)); //disable int REG32_VAL(__GPIO_BASE + offset) = reg; REG32_VAL(__GPIO_BASE+0x0360) = 1<<num; //clear interrupt status msleep(5); return 0; } int wmt_enable_gpirq(void) { int num = irq_gpio; if(num > 11) return -1; if(num<4) REG32_VAL(__GPIO_BASE+0x0300) |= 1<<(num*8+7); //enable interrupt else if(num >= 4 && num < 8) REG32_VAL(__GPIO_BASE+0x0304) |= 1<<((num-4)*8+7); //enable interrupt else REG32_VAL(__GPIO_BASE+0x0308) |= 1<<((num-8)*8+7); //enable interrupt return 0; } int wmt_disable_gpirq(void) { int num = irq_gpio; if(num > 11) return -1; if(num<4) REG32_VAL(__GPIO_BASE+0x0300) &= ~(1<<(num*8+7)); //enable interrupt else if(num >= 4 && num < 8) REG32_VAL(__GPIO_BASE+0x0304) &= ~(1<<((num-4)*8+7)); //enable interrupt else REG32_VAL(__GPIO_BASE+0x0308) &= ~(1<<((num-8)*8+7)); //enable interrupt return 0; } int wmt_get_tsirqnum(void) { return IRQ_GPIO; } int wmt_ts_set_rawcoord(unsigned short x, unsigned short y) { g_evLast.x = x; g_evLast.y = y; //dbg("raw(%d,%d)*\n", x, y); return 0; } static void wmt_ts_platform_release(struct device *device) { return; } static struct platform_device wmt_ts_plt_device = { .name = TS_DRIVER_NAME, .id = 0, .dev = { .release = wmt_ts_platform_release, }, // .num_resources = ARRAY_SIZE(wm9715_ts_resources), // .resource = wm9715_ts_resources, }; static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) { dbg("ts suspend....\n"); return l_tsdev->suspend(pdev, state); } static int wmt_ts_resume(struct platform_device *pdev) { dbg("ts resume....\n"); return l_tsdev->resume(pdev); } static int wmt_ts_probe(struct platform_device *pdev) { if (l_tsdev->probe != NULL) return l_tsdev->probe(pdev); else return 0; } static int wmt_ts_remove(struct platform_device *pdev) { if (l_tsdev->remove != NULL) return l_tsdev->remove(pdev); else return 0; } static struct platform_driver wmt_ts_plt_driver = { .driver = { .name = TS_DRIVER_NAME, .owner = THIS_MODULE, }, .probe = wmt_ts_probe, .remove = wmt_ts_remove, .suspend = wmt_ts_suspend, .resume = wmt_ts_resume, }; static int wmt_check_touch_env(void) { int ret = 0; int len = 150; char retval[150] = {0},*p=NULL; int Enable=0,Gpio=0,PX=0,PY=0; char* s=NULL; // Get u-boot parameter ret = wmt_getsyspara("wmt.io.touch", retval, &len); if(ret){ errlog("Read wmt.io.touch Failed.\n"); return -EIO; } sscanf(retval,"%d:",&Enable); //check touch enable if(Enable == 0){ errlog("Touch Screen Is Disabled.\n"); return -ENODEV; } p = strchr(retval,':'); p++; if(strncmp(p, l_tsdev->ts_id,strlen(l_tsdev->ts_id))){//check touch ID errlog("[WMTENV] %s is not found\n", l_tsdev->ts_id); return -ENODEV; } // get firmwareid s = p+strlen(l_tsdev->ts_id)+1; //point to firmware id p = strchr(p,':'); memset(l_firmid,0,sizeof(l_firmid)); len = p-s; if (len>=20) { len = 19; } strncpy(l_firmid,s,len); p++; sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d",&Gpio,&PX,&PY,&rst_gpio, &l_xaxis,&l_xdirect, &l_yaxis,&l_ydirect, &l_cutedge); irq_gpio = Gpio; panelres_x = PX; panelres_y = PY; dbg("p.x=%d,p.y=%d,gpio=%d,resetgpio=%d,\nx-axis=%d,x_dir=%d,y-axis=%d,y_dir=%d,cutedge=%d\nfirmwareid:%s\n", panelres_x, panelres_y, irq_gpio, rst_gpio, l_xaxis,l_xdirect,l_yaxis,l_ydirect,l_cutedge, l_firmid); 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]) lcd_exchg = 1; } return 0; } struct i2c_board_info ts_i2c_board_info = { .type = WMT_TS_I2C_NAME, .flags = 0x00, .addr = WMT_TS_I2C_ADDR, .platform_data = NULL, .archdata = NULL, .irq = -1, }; static int ts_i2c_register_device (void) { struct i2c_board_info *ts_i2c_bi; struct i2c_adapter *adapter = NULL; //struct i2c_client *client = NULL; ts_i2c_bi = &ts_i2c_board_info; adapter = i2c_get_adapter(1);/*in bus 1*/ if (NULL == adapter) { printk("can not get i2c adapter, client address error\n"); return -1; } l_client = i2c_new_device(adapter, ts_i2c_bi); if (l_client == NULL) { printk("allocate i2c client failed\n"); return -1; } i2c_put_adapter(adapter); return 0; } static void ts_i2c_unregister_device(void) { if (l_client != NULL) { i2c_unregister_device(l_client); l_client = NULL; } } struct i2c_client* ts_get_i2c_client(void) { return l_client; } static int __init wmt_ts_init(void) { int ret = 0; if(wmt_check_touch_env()) return -ENODEV; if (ts_i2c_register_device()<0) { dbg("Error to run ts_i2c_register_device()!\n"); return -1; } mutex_init(&cal_mutex); if (l_tsdev->init() < 0){ dbg("Errors to init %s ts IC!!!\n", l_tsdev->ts_id); ret = -1; goto err_init; } // Create device node /* if (register_chrdev (TS_MAJOR, TS_NAME, &wmt_ts_fops)) { printk (KERN_ERR "wmt touch: unable to get major %d\n", TS_MAJOR); return -EIO; } l_dev_class = class_create(THIS_MODULE, TS_NAME); if (IS_ERR(l_dev_class)){ ret = PTR_ERR(l_dev_class); printk(KERN_ERR "Can't class_create touch device !!\n"); return ret; } l_clsdevice = device_create(l_dev_class, NULL, MKDEV(TS_MAJOR, 0), NULL, TS_NAME); if (IS_ERR(l_clsdevice)){ ret = PTR_ERR(l_clsdevice); printk(KERN_ERR "Failed to create device %s !!!",TS_NAME); return ret; } */ // register device and driver of platform ret = platform_device_register(&wmt_ts_plt_device); if(ret){ errlog("wmt ts plat device register failed!\n"); return ret; } ret = platform_driver_register(&wmt_ts_plt_driver); if(ret){ errlog("can not register platform_driver_register\n"); platform_device_unregister(&wmt_ts_plt_device); return ret; } klog("%s driver init ok!\n",l_tsdev->ts_id); return 0; err_init: ts_i2c_unregister_device(); return ret; } static void __exit wmt_ts_exit(void) { dbg("%s\n",__FUNCTION__); l_tsdev->exit(); platform_driver_unregister(&wmt_ts_plt_driver); platform_device_unregister(&wmt_ts_plt_device); //device_destroy(l_dev_class, MKDEV(TS_MAJOR, 0)); //unregister_chrdev(TS_MAJOR, TS_NAME); //class_destroy(l_dev_class); mutex_destroy(&cal_mutex); ts_i2c_unregister_device(); } module_init(wmt_ts_init); module_exit(wmt_ts_exit); MODULE_LICENSE("GPL");