www.pudn.com > ads7846.rar > 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 

#include 
#include 
#include 

#include "ads7843_ts.h"



#define PRINTK printk
#define DELAY 30

static 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);