📄 ads7843_ts.c
字号:
/******************************************************************************** File name : ads7843.c** ** Description :** ADS7843(Touch Screen Controller)** ** Compile environment and method of compile & link** gcc version 2.95.2 20000313 (Debian GNU/Linux)**** Usage :** Touch screen controller Device Driver for X-Hyper25X Board ** ** License : ** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU General Public License version 2 as** published by the Free Software Foundation**** Modification history :** Date Version Programmer & Tester Modify issue** 2002.5.1 0.1 Heo young Wook Create** 2003.8.1 0.2 Heo young Wook interrupt modify*********************************************************************************/#include <linux/config.h>#include <linux/types.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/string.h>#include <linux/devfs_fs_kernel.h>#include <asm/uaccess.h>#include <asm/hardware.h>#include <asm/irq.h>#include "ads7843_ts.h"#define PRINTK printk#define DELAY 30static int head, tail;static TS_EVENT cur_data, samples[3], buf[BUFSIZE];static struct fasync_struct *fasync;static unsigned long in_timehandle = 0;unsigned int count =0;static void ts_clear(void);static void print_par(void);static void read_xy(void);void ads7843_din(char command){ int i; XHYPER255_ClearBit(0, ADS7843_CS); udelay(DELAY); for(i = 0; i < 8; i++) { XHYPER255_ClearBit(0, ADS7843_CLK); if((command >> i)&0x1){ XHYPER255_SetBit(0, ADS7843_DIN); } else { XHYPER255_ClearBit(0, ADS7843_DIN); } udelay(DELAY); XHYPER255_SetBit(0, ADS7843_CLK); }}void ads7843_askx(void){ ads7843_din(SPIMDATA_ASKX);}void ads7843_asky(void){ ads7843_din(SPIMDATA_ASKY);}void ads7843_nop(void){ ads7843_din(SPIMDATA_NOP);}int sa1100_ts_measure_x(void){ char i; int touch_data = 0; XHYPER255_ClearBit(0, ADS7843_CS); udelay(DELAY); for(i = 0; i < 8; i++) { XHYPER255_ClearBit(0, ADS7843_CLK); udelay(DELAY); if(( SPIMDATA_ASKX >> i) & 0x01){ XHYPER255_SetBit(0, ADS7843_DIN); } else { XHYPER255_ClearBit(0, ADS7843_DIN); } udelay(DELAY); XHYPER255_SetBit(0, ADS7843_CLK); } XHYPER255_ClearBit(0, ADS7843_CLK); udelay(DELAY); while(!(GPLR0 & GPIO_bit(ADS7843_BUSY))) printk("BUSY1\n"); XHYPER255_ClearBit(0, ADS7843_CLK); for(i = 0; i < 15; i++) { touch_data <<= 1; if(GPLR0 & GPIO_bit(ADS7843_DOUT)){ touch_data |= 0x01; } else { touch_data &= 0xffffe; } XHYPER255_SetBit(0, ADS7843_CLK); udelay(DELAY); XHYPER255_ClearBit(0, ADS7843_CLK); } touch_data >>= 3; return (touch_data & 0xfff);}int sa1100_ts_measure_y(void){ char i; int touch_data = 0; XHYPER255_ClearBit(0, ADS7843_CS); udelay(DELAY); for(i = 0; i < 8; i++) { XHYPER255_ClearBit(0, ADS7843_CLK); udelay(DELAY); if(( SPIMDATA_ASKY >> i) & 0x01){ XHYPER255_SetBit(0, ADS7843_DIN); } else { XHYPER255_ClearBit(0, ADS7843_DIN); } udelay(DELAY); XHYPER255_SetBit(0, ADS7843_CLK); } XHYPER255_ClearBit(0, ADS7843_CLK); udelay(DELAY); while(!(GPLR0 & GPIO_bit(ADS7843_BUSY))) printk("BUSY2\n"); XHYPER255_ClearBit(0, ADS7843_CLK); for(i = 0; i < 15; i++) { touch_data <<= 1; if(GPLR0 & GPIO_bit(ADS7843_DOUT)){ touch_data |= 0x01; } else { touch_data &= 0xffffe; } XHYPER255_SetBit(0, ADS7843_CLK); udelay(DELAY); XHYPER255_ClearBit(0, ADS7843_CLK); } touch_data >>= 3; return (touch_data & 0xfff);}void Ads7843_Enable_IRQ(void){ ADS7843_CS_LOW // CS Low udelay(DELAY); ads7843_din(SPIMDATA_NOP); udelay(DELAY); ADS7843_CS_HIGH // CS High - Conversion END}static int ads7843_ts_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){/* Microwindows style (should change to TS_CAL when the specification is ready) */ switch (cmd) { case 3: raw_max_x = arg; break; case 4: raw_max_y = arg; break; case 5: res_x = arg; break; case 6: res_y = arg; break; case 10: raw_min_x = arg; break; case 11: raw_min_y = arg; break; case 12:/* New attribute for portrait modes */ xyswap = arg;/* Allen Add */ case 13: /* 0 = Enable calibration ; 1 = Calibration OK */ cal_ok = arg; case 14: /* Clear all buffer data */ ts_clear(); break; case 15: /* X axis reversed setting */ x_rev = arg; break; case 16: /* Y axis reversed setting */ y_rev = arg; break; case 17: /* Clear all buffer data */ print_par(); break;/* Allen */ } return 0;}static void ts_clear(void){ int i; for (i=0; i < BUFSIZE; i++) { buf[i].pressure=(short)NULL; buf[i].x=(int)NULL; buf[i].y=(int)NULL; buf[i].millisecs=(int)NULL; } head = 0; tail = 0;}static void print_par(void){ printk(" Kernel ==> cal_ok = %d\n",cal_ok); printk(" Kernel ==> raw_max_x = %d\n",raw_max_x); printk(" Kernel ==> raw_max_y = %d\n",raw_max_y); printk(" Kernel ==> res_x = %d\n",res_x); printk(" Kernel ==> res_y = %d\n",res_y); printk(" Kernel ==> raw_min_x = %d\n",raw_min_x); printk(" Kernel ==> raw_min_y = %d\n",raw_min_y); printk(" Kernel ==> xyswap = %d\n",xyswap); printk(" Kernel ==> x_rev = %d\n",x_rev); printk(" Kernel ==> y_rev = %d\n",y_rev);}static void new_data(void){ static TS_EVENT last_data = { 0, 0, 0, 0 }; static TS_EVENT temp_data[2]; int diff0, diff1, diff2, diff3=0; if (cur_data.pressure) { diff0 = abs(samples[0].x - samples[1].x); diff1 = abs(samples[1].x - samples[2].x); diff2 = abs(samples[2].x - samples[0].x); if (diff0 > XLIMIT || diff1 > XLIMIT || diff2 > XLIMIT) return; if (diff0 < diff1) { if (diff2 < diff0) temp_data[0].x = (samples[0].x + samples[2].x) / 2; else temp_data[0].x = (samples[0].x + samples[1].x) / 2; } else { if (diff2 < diff3) temp_data[0].x = (samples[2].x + samples[0].x) / 2; else temp_data[0].x = (samples[2].x + samples[1].x) / 2; } diff0 = abs(samples[0].y - samples[1].y); diff1 = abs(samples[1].y - samples[2].y); diff2 = abs(samples[2].y - samples[0].y); if (diff0 > YLIMIT || diff1 > YLIMIT || diff2 > YLIMIT || diff3 > YLIMIT) return; if (diff0 < diff2) { if (diff2 < diff3) temp_data[0].y = (samples[0].y + samples[2].y) / 2; else temp_data[0].y = (samples[0].y + samples[1].y) / 2; } else { if (diff2 < diff3) temp_data[0].y = (samples[2].y + samples[0].y) / 2; else temp_data[0].y = (samples[2].y + samples[1].y) / 2; } if(!last_data.x && !last_data.y) { last_data = temp_data[0]; temp_data[1] = temp_data[0]; return; } cur_data.x = last_data.x; cur_data.y = last_data.y; last_data = temp_data[1]; temp_data[1] = temp_data[0]; } else {/* Reset jitter detection on pen release */ last_data.x = 0; last_data.y = 0; } cur_data.millisecs = jiffies; if (head != tail) { int last = head--; if (last < 0) last = BUFSIZE - 1; } buf[head] = cur_data; if (++head == BUFSIZE) head = 0; if (head == tail && tail++ == BUFSIZE) tail = 0; if (fasync) kill_fasync(&fasync, SIGIO, POLL_IN);// printk("X = %d, Y = %d \n",cur_data.x, cur_data.y); wake_up_interruptible(&queue);}static TS_EVENT get_data(void){ int last = tail; if (++tail == BUFSIZE) tail = 0; return buf[last];}static void wait_for_action(void){ set_GPIO_IRQ_edge(IRQ_GPIO_ADS7843, GPIO_FALLING_EDGE); enable_irq(IRQ_GPIO_ADS7843);}static unsigned int ads7843_ts_poll(struct file *filp, poll_table *wait){ poll_wait(filp, &queue, wait); if (head != tail) return POLLIN | POLLRDNORM; return 0;}static ssize_t ads7843_ts_read(struct file *filp, char *buf, size_t count, loff_t *l){ DECLARE_WAITQUEUE(wait, current); int i; TS_EVENT t; short out_buf[4]; short tmp; if (head == tail) { if (filp->f_flags & O_NONBLOCK) return -EAGAIN; add_wait_queue(&queue, &wait); current->state = TASK_INTERRUPTIBLE; while ((head == tail) && !signal_pending(current)) { schedule(); current->state = TASK_INTERRUPTIBLE; } current->state = TASK_RUNNING; remove_wait_queue(&queue, &wait); } for (i = count; i >= sizeof(out_buf); i -= sizeof(out_buf), buf += sizeof(out_buf)) { if (head == tail) break; t = get_data(); out_buf[0] = t.pressure; if(xyswap) { tmp = t.y; t.y = t.x; t.x = tmp; } if (cal_ok) { out_buf[1] = (x_rev) ? ((raw_max_x - t.x) * res_x) / (raw_max_x - raw_min_x) : ((t.x - raw_min_x) * res_x) / (raw_max_x - raw_min_x); out_buf[2] = (y_rev) ? ((raw_max_y - t.y) * res_y) / (raw_max_y - raw_min_y) : ((t.y - raw_min_y) * res_y) / (raw_max_y - raw_min_y); out_buf[1] = out_buf[1] < res_x ? out_buf[1] : res_x - 1; out_buf[2] = out_buf[2] < res_y ? out_buf[2] : res_y - 1; out_buf[1] = out_buf[1] >= 0 ? out_buf[1] : 0; out_buf[2] = out_buf[2] >= 0 ? out_buf[2] : 0; } else { out_buf[1] = t.y; out_buf[2] = t.x; } out_buf[3] = t.millisecs; copy_to_user(buf, &out_buf, sizeof(out_buf)); } return count - i;}static void ads7843_ts_timer(unsigned long);static int ads7843_ts_starttimer(void){ in_timehandle++; init_timer(&timer); timer.function = ads7843_ts_timer; timer.expires = jiffies + HZ / 100; add_timer(&timer); return 0;}static void ads7843_ts_timer(unsigned long data){ in_timehandle--; if (GPLR0 & GPIO_bit(ADS7843_PENIRQ)){ cur_data.pressure = 0; new_data(); wait_for_action(); } else if(samples[0].x!=0 || samples[1].x!=0 || samples[2].x!=0) read_xy();}static void read_xy(void){ disable_irq(IRQ_GPIO_ADS7843); ads7843_askx(); udelay(200); ads7843_asky(); samples[0].x = sa1100_ts_measure_x(); samples[0].y = sa1100_ts_measure_y(); samples[1].x = sa1100_ts_measure_x(); samples[1].y = sa1100_ts_measure_y(); samples[2].x = sa1100_ts_measure_x(); samples[2].y = sa1100_ts_measure_y(); cur_data.pressure = 1; new_data(); ads7843_ts_starttimer();}static int ads7843_ts_fasync(int fd, struct file *filp, int on){ int retval; retval = fasync_helper(fd, filp, on, &fasync); if (retval < 0) return retval; return 0;}static int ads7843_ts_open(struct inode *inode, struct file *filp){ ts_clear(); MOD_INC_USE_COUNT; return 0;}static int ads7843_ts_release(struct inode *inode, struct file *filp){ ts_clear(); ads7843_ts_fasync(-1, filp, 0); MOD_DEC_USE_COUNT; return 0;}static void ads7843_ts_interrupt(int irq, void *dev_id, struct pt_regs *regs){ if (in_timehandle > 0) return; read_xy();}static struct file_operations ads7843_ts_fops = { read: ads7843_ts_read, poll: ads7843_ts_poll, ioctl: ads7843_ts_ioctl, fasync: ads7843_ts_fasync, open: ads7843_ts_open, release:ads7843_ts_release,};int sa1100_ts_init(void){ raw_max_x = 965; raw_max_y = 970; raw_min_x = 23; raw_min_y = 45; res_x =640; res_y =480; xyswap = 0; head = 0; tail = 0; cal_ok = 1; x_rev = 0; y_rev = 1; init_waitqueue_head(&queue); wait_for_action(); return 0;}static devfs_handle_t devfs_handle, devfs_ts_dir;int __init ads7843_ts_init(void){ int ret; if ((ret=devfs_register_chrdev(TS_MAJOR, TS_NAME, &ads7843_ts_fops))!=0) { printk("registering of " TS_NAME " is failed\n"); return ret; } devfs_ts_dir = devfs_mk_dir(NULL, "touchscreen", NULL); devfs_handle = devfs_register(devfs_ts_dir, "0raw", DEVFS_FL_DEFAULT, TS_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &ads7843_ts_fops, NULL); if ((ret = request_irq(IRQ_GPIO_ADS7843, ads7843_ts_interrupt, SA_SHIRQ|SA_INTERRUPT, TS_NAME, dev_id))) { printk("ads7843_ts_init: failed to register IRQ\n"); free_irq(IRQ_GPIO_ADS7843, dev_id); return ret; } if ((ret = sa1100_ts_init()) != 0) { free_irq(IRQ_GPIO_ADS7843, dev_id); return ret; } GPDR0 &= ~GPIO_bit(ADS7843_BUSY); GPDR0 &= ~GPIO_bit(ADS7843_DOUT); Ads7843_Enable_IRQ(); printk("ads7843 touch screen driver initialized\n"); return 0;}void __exit ads7843_ts_cleanup(void){ if (in_timehandle) del_timer(&timer); free_irq(IRQ_GPIO_ADS7843, dev_id); devfs_unregister_chrdev(TS_MAJOR, TS_NAME); printk("ads7843 touch screen driver removed\n");}module_init(ads7843_ts_init);module_exit(ads7843_ts_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -