Touch Screen Driver for Linux2.6.xx+ARM9

来源:互联网 发布:mysql事务回滚 原理 编辑:程序博客网 时间:2024/04/30 20:14

/**
  * Driver for Touch Screen,using input-subsystem way
  */

----------------------------------------------------------driver---------------------------------------------------------------
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
  
//#include <asm/plat-s3c24xx/ts.h>
  
#include <asm/arch/regs-adc.h>
#include <asm/arch/regs-gpio.h>

//#define DRIVER_NAME "czinputsubsys_ts"
static char *s3c2410ts_name = "s3c2410 TouchScreen";

static void touch_timer_fire(unsigned long data);
static irqreturn_t stylus_action(int irq, void *dev_id);
static irqreturn_t stylus_updown(int irq, void *dev_id);
 

#define WAIT4INT(x) (((x)<<8) | \
   S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
   S3C2410_ADCTSC_XY_PST(3))
 
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
   S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))


static struct input_dev *pczinput_dev;
static void __iomem *pczbase_addr;
static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);

 struct s3c2410ts {
  //struct input_dev *dev;
  long xp;
  long yp;
  int count;
  int shift;
 };

 static struct s3c2410ts ts;

 static void touch_timer_fire(unsigned long data)
 {
  unsigned long data0;
  unsigned long data1;
  int updown;
 
  data0 = ioread32(pczbase_addr+S3C2410_ADCDAT0);
  data1 = ioread32(pczbase_addr+S3C2410_ADCDAT1);
 
  updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
 
  if (updown) {
   stylus_updown(0,NULL);
   //iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, pczbase_addr+S3C2410_ADCTSC);
   //iowrite32(ioread32(pczbase_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, pczbase_addr+S3C2410_ADCCON);

  } else {
   printk("driver:stylus up from touch_timer_fire\n");

   ts.xp = 0;
      ts.yp = 0;

   ts.count = 0;
 
   input_report_key(pczinput_dev, BTN_TOUCH, 0);
   input_report_abs(pczinput_dev, ABS_PRESSURE, 0);
   input_sync(pczinput_dev);
 
   iowrite32(WAIT4INT(0), pczbase_addr+S3C2410_ADCTSC);//waiting for pen down
  }
 }
    
 static irqreturn_t stylus_action(int irq, void *dev_id)
 {
  unsigned long data0;
  unsigned long data1;
 
  data0 = ioread32(pczbase_addr+S3C2410_ADCDAT0);
  data1 = ioread32(pczbase_addr+S3C2410_ADCDAT1);
 
  ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;//x point
  ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;//y point
  ts.count++;//times

  if (ts.count < (1<<ts.shift)) {
     //iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, pczbase_addr+S3C2410_ADCTSC);
     //iowrite32(ioread32(pczbase_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, pczbase_addr+S3C2410_ADCCON);
     stylus_updown(0,NULL);

  } else {
                if (ts.count != 0) {
               long tmp;
             tmp = ts.xp;
             ts.xp = ts.yp;
             ts.yp = tmp;
         
            ts.xp >>= ts.shift;
            ts.yp >>= ts.shift;
            printk("ts.xp is:%d, ts.yp is:%d\n",ts.xp,ts.yp);
        
            input_report_abs(pczinput_dev, ABS_X, ts.xp);
            input_report_abs(pczinput_dev, ABS_Y, ts.yp);
        
            input_report_key(pczinput_dev, BTN_TOUCH, 1);
            input_report_abs(pczinput_dev, ABS_PRESSURE, 1);
            input_sync(pczinput_dev);
  
            iowrite32(WAIT4INT(1), pczbase_addr+S3C2410_ADCTSC);//waiting for pen up
           }

           mod_timer(&touch_timer, jiffies+HZ/100);
          //iowrite32(WAIT4INT(1), pczbase_addr+S3C2410_ADCTSC);
     }

  return IRQ_HANDLED;
 }

 static irqreturn_t stylus_updown(int irq, void *dev_id)
 {
  unsigned long data0;
  unsigned long data1;
  int updown;
 
  data0 = ioread32(pczbase_addr+S3C2410_ADCDAT0);
  data1 = ioread32(pczbase_addr+S3C2410_ADCDAT1);
 
  updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT1_UPDOWN));
    printk("driver:stylus %d\n",updown);
 // if (updown)
  // touch_timer_fire(0);
 if (updown){
 printk("driver:stylus down\n");
 iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, pczbase_addr+S3C2410_ADCTSC);//set AUTOPST mode
 iowrite32(ioread32(pczbase_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, pczbase_addr+S3C2410_ADCCON);//start adc
 //iowrite32(ioread32(pczbase_addr+S3C2410_ADCTSC) |WAIT4INT(1), pczbase_addr+S3C2410_ADCTSC);
 } else  {
   printk("driver:stylus up from stylus_updown\n");
   ts.xp = 0;
   ts.yp = 0;
   
   ts.count = 0;
   
   input_report_key(pczinput_dev, BTN_TOUCH, 0);
   input_report_abs(pczinput_dev, ABS_PRESSURE, 0);
   input_sync(pczinput_dev);
   
   iowrite32(WAIT4INT(0), pczbase_addr+S3C2410_ADCTSC);//waiting for pen down
   }

  return IRQ_HANDLED;
 }


 static struct clk *adc_clock;
 
 static int czinputsubsys_ts_init(void)
 {
 printk("driver:czinputsubsys_ts_init in\n");

 adc_clock = clk_get(NULL, "adc");
 clk_enable(adc_clock);

 
 pczbase_addr=ioremap(S3C2410_PA_ADC,0x20);
 
 //s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);//2440 don't need this cfgpin!

 //ADCCON setup
 iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(49&0xFF),pczbase_addr+S3C2410_ADCCON);
 //ADCTSC setup
 iowrite32(WAIT4INT(0), pczbase_addr+S3C2410_ADCTSC);//waiting for pen down
 //ADCDLY setup
 iowrite32(0xffff & 0xffff,  pczbase_addr+S3C2410_ADCDLY);


 pczinput_dev = input_allocate_device();
 
 pczinput_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
 pczinput_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);

 input_set_abs_params(pczinput_dev, ABS_X, 0, 0x3FF, 0, 0);
 input_set_abs_params(pczinput_dev, ABS_Y, 0, 0x3FF, 0, 0);
 input_set_abs_params(pczinput_dev, ABS_PRESSURE, 0, 1, 0, 0);

 pczinput_dev->name = s3c2410ts_name;

 ts.shift = 4;

 /* Get irqs */
 request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,"s3c2410_action", pczinput_dev);
 request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM | SA_SHIRQ, "s3c2410_action", pczinput_dev);

 input_register_device(pczinput_dev);

 return 0;
 }

static void czinputsubsys_ts_exit(void)
{
 printk("driver:czinputsubsys_ts_exit in\n");

 disable_irq(IRQ_ADC);
 disable_irq(IRQ_TC);
 free_irq(IRQ_TC,pczinput_dev);
 free_irq(IRQ_ADC,pczinput_dev);

 if (adc_clock) {
 clk_disable(adc_clock);
 clk_put(adc_clock);
 adc_clock = NULL;
 }

 input_unregister_device(pczinput_dev);
 input_free_device(pczinput_dev);
 iounmap(pczbase_addr);
 del_timer(&touch_timer);

 return;
}
 
 module_init(czinputsubsys_ts_init);
 module_exit(czinputsubsys_ts_exit);
 MODULE_AUTHOR("chaozang(cz) <zangchao.cn@gmail.com>,copy frm teacher:weidongshan,thanks so much!");
 MODULE_LICENSE("GPL");

----------------------------------------------------test commands----------------------------------------------------------

# ls /dev/event0

#hexdump /dev/event0

-----------------------------------------------------------

Contact: zangchao.cn@gmail.com

 

原创粉丝点击