⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsc2003.c

📁 TSC2003 触摸屏 支持mips 支持QTE
💻 C
字号:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <linux/signal.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <asm/semaphore.h>
#include <asm/atomic.h>

#define USE_ASYNC

#define IIC_MAJOR   0 /*the predicted master device number*/

#define I2C_START 0x80
#define I2C_STOP 0x40
#define I2C_READ 0x20
#define I2C_WRITE 0x10
#define I2C_WACK 0x8
#define I2C_IACK 0x1
#define I2C_RUN 0x2
#define I2C_BUSY 0x40
#define I2C_RACK 0x80
#define GC_SOC_I2C_BASE  0xbf0040d0
#define GC_SOC_I2C_PRER_LO (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x0)
#define GC_SOC_I2C_PRER_HI (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x1)
#define GC_SOC_I2C_CTR     (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x2)
#define GC_SOC_I2C_TXR     (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x3)
#define GC_SOC_I2C_RXR     (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x3)
#define GC_SOC_I2C_CR      (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x4)
#define GC_SOC_I2C_SR      (volatile unsigned char *)(GC_SOC_I2C_BASE + 0x4)
#define GPIO_OE_15_8        (volatile unsigned char *)( 0xbF004100 + 0x01 ) 



//for LPB MISC

#define GPIO_OE_15_8        (volatile unsigned char *)( 0xbF004100 + 0x01 ) 
#define GPIO_I_15_8	    (volatile unsigned char *)( 0xbf004100 + 0x11 )	
//for IIC
#define  HSB_MISC_REG_BASE   0xbF003200
#define  INT_EDGE	     	(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x04)
#define  INT_STEER	    	(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x08)
#define  INT_POL		(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x0c)
#define  INT_SET		(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x10)
#define  INT_CLR		(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x14)
#define  INT_EN			(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x18)
#define  INT_ISR        	(volatile unsigned int  *)(HSB_MISC_REG_BASE+0x1c)

#define  INT_EDGE_GPIO13       22//interupt number

#define u8 unsigned char

static int tsc2003_major = IIC_MAJOR;
static struct cdev tsc2003_cdev;/*global variable for device*/

static  char *DEVICE_NAME = "h3600_tsraw";

MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
MODULE_DESCRIPTION("TSC2003 touchscreen driver");
MODULE_LICENSE("GPL");

//COMMAND
#define TSC_ADDR 	0x90
#define INIT_TSC  0xB6
#define MEASURE_X	0xC0
#define MEASURE_Y	0xD0  
#define RESERV_CMD 0x70
static unsigned  short pos_x ,pos_y;
typedef struct {
  unsigned short pressure;
  unsigned short x;
  unsigned short y;
  unsigned short pad;
} TS_RET;

#define MAX_TS_BUF	16	/* how many do we want to buffer */
static atomic_t timer_sw;

typedef struct {
	volatile unsigned int penStatus;		/* PEN_UP, PEN_DOWN, PEN_SAMPLE */
	TS_RET buf[MAX_TS_BUF];		/* protect against overrun */
	unsigned int head, tail;	/* head and tail for queued events */
	wait_queue_head_t wq;
	struct semaphore sem;
	spinlock_t lock;
#ifdef USE_ASYNC
	struct fasync_struct *aq;
#endif
} TS_DEV; 

enum PEN_Stat{
		PEN_UP = 0,
		PEN_DOWN = 1,// 
		PEN_PROCESS,
};

static TS_DEV tsdev;
#define BUF_HEAD	(tsdev.buf[tsdev.head])
#define BUF_TAIL	(tsdev.buf[tsdev.tail])
#define INCBUF(x,mod) 	((++(x)) & ((mod) - 1))
static struct timer_list ts_timer;

//#define TS_TIMER_DELAY    (HZ/100) //10ms
#define TS_TIMER_DELAY    (HZ/100) //10ms


static int myi2c_init(int v)
{
static int inited=0;
if(inited)return 0;
inited=1;
 * GC_SOC_I2C_PRER_LO = 0x63;//50K
 * GC_SOC_I2C_PRER_HI = 0x0;
 * GC_SOC_I2C_CTR = 0x80;
  if(v)printk("* GC_SOC_I2C_PRER_LO=0x%x\n",* GC_SOC_I2C_PRER_LO);
  if(v)printk("* GC_SOC_I2C_PRER_HI=0x%x\n",* GC_SOC_I2C_PRER_HI);
  if(v)printk("* GC_SOC_I2C_CTR=0x%x\n",* GC_SOC_I2C_CTR);
  if((* GC_SOC_I2C_PRER_LO != 0x63) || (* GC_SOC_I2C_PRER_HI != 0x0))
  return -1;
  else return 0;
}

static int myi2c_write(u8 cmd,int v)
{
  spin_lock_irq(&(tsdev.lock));
  unsigned char tmp;
  myi2c_init(v);

  * GC_SOC_I2C_TXR = 0x90;
  * GC_SOC_I2C_CR  = 0x90;
  do  tmp = * GC_SOC_I2C_SR;
  while( tmp & 0x02);
  if((* GC_SOC_I2C_SR) & 0x80)
  {
     if(v)printk("TSC2003 write slave addresss dnot receive ack\n");
	     return 1;
   }
   else
   if(v)printk("TSC2003 write slave addresss receive ack\n");

  * GC_SOC_I2C_TXR = cmd;//
  * GC_SOC_I2C_CR  = 0x50;//contain stop signal
  do  tmp = * GC_SOC_I2C_SR;
  while( tmp & 0x02);
  if((* GC_SOC_I2C_SR) & 0x80)
  {
     if(v)printk("TSC2003 write slave addresss dnot receive ack\n");
      	    return 2;
   }
   else
   if(v)printk("TSC2003 write slave command receive ack\n");

  if((* GC_SOC_I2C_SR) & 0x40)
  {
     if(v)printk("bus is busy\n");
	  return 3;
   }
   else
   if(v)printk("i2c bus is idle\n");
	udelay(20);

   spin_unlock_irq(&(tsdev.lock));

   return 0;
}

static int myi2c_read(u8 cmd,int v)
{
   spin_lock_irq(&(tsdev.lock));
   unsigned short  val;
   unsigned char tmp;
   unsigned char result[2];
	myi2c_init(v);
	* GC_SOC_I2C_TXR = 0x91;
   *GC_SOC_I2C_CR  = 0x90;
  do  tmp = * GC_SOC_I2C_SR;
  while( tmp & 0x02);
  if((* GC_SOC_I2C_SR) & 0x80)
  {
     if(v)printk("TSC2003 read slave addresss dnot receive ack\n");
      
   }
   else
   if(v)printk("TSC2003 read  slave addresss receive ack\n");
  
  
  * GC_SOC_I2C_CR  = 0x20;
  do  tmp = * GC_SOC_I2C_SR;
  while( tmp & 0x02);

    result[1] = * GC_SOC_I2C_TXR;
  * GC_SOC_I2C_CR  = 0x48;//STOP
    result[0] = * GC_SOC_I2C_TXR;
	 val = result[1];
	 val=val<<4;
	 val+=result[0]>>4;
	if(cmd == MEASURE_X)
	{
	pos_x = val;
	}
 else
 	{

	pos_y = val;

 	}

    if(v) printk("GPIO_I_15_8=%x\n", * GPIO_I_15_8);
    spin_unlock_irq(&(tsdev.lock));
	return 0;


}

static int measure_pos(u8 cmd ,int v)
{
	if ( myi2c_write(cmd,v))
	{
		return 1;
	}
	myi2c_read(cmd,v);
	return 0;
}

static int IsPen_down(void)
{
	
	if( (*GPIO_I_15_8) & (1<<5))
		return 0;
	else
		return 1;//pen down

}

static int measure_xy(void)
{
	/*if(measure_pos(MEASURE_X ,1))
		{
			return 1;
		}
	if(measure_pos(MEASURE_Y ,1))
		{
			return 2;
		}*/
	int i=0;
	do{
		i++;
	}while((measure_pos(MEASURE_X ,0)|measure_pos(MEASURE_Y ,0)) && (i<5) );
	//printk("measurn_xy\n");
	return 0;
}

static void ts_timer_handler(unsigned long data)
{
	//spin_lock_irq(&(tsdev.lock));//add for test
	if(down_trylock(&tsdev.sem))
	{
		printk("handler can't get sem\n");
		
		return;
	}
	if(IsPen_down())
	{
	measure_xy();
	BUF_HEAD.x = pos_x;
	BUF_HEAD.y = pos_y;
	BUF_HEAD.pressure  = PEN_DOWN;	
	tsdev.penStatus = PEN_DOWN;
	ts_timer.expires = jiffies + TS_TIMER_DELAY;
	
	add_timer(&ts_timer);
	tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);
	wake_up_interruptible(&(tsdev.wq));
	
	}
	else
	{
	tsdev.penStatus = PEN_UP;
	BUF_HEAD.x = pos_x ;
	BUF_HEAD.y = pos_y ;
	BUF_HEAD.pressure = PEN_UP;	
	tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);
	wake_up_interruptible(&(tsdev.wq));
	tsdev.penStatus = PEN_UP;

		if(atomic_read(&timer_sw) == 1)
		{

			atomic_set(&timer_sw , 0);
			del_timer(&ts_timer);
		}
	//printk("timer_list =0x%0x\n",*INT_POL);

	}


#ifdef USE_ASYNC	
	if(tsdev.aq)
		kill_fasync(&(tsdev.wq),SIGIO,POLL_IN);
#endif
	//spin_unlock_irq(&(tsdev.lock));//add for test
	up(&tsdev.sem);
}

//timer for release touch screen

static int tsRead(TS_RET * ts_ret)
{
	
	ts_ret->x = BUF_TAIL.x;
	ts_ret->y = BUF_TAIL.y;
	ts_ret->pressure = BUF_TAIL.pressure;
	//printk("\nx=%d,y=%d,press = %d \n",ts_ret->x ,ts_ret->y,ts_ret->pressure );
	tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);
	//spin_unlock_irq(&(tsdev.lock));
	return sizeof(TS_RET);
}

static ssize_t pm3210_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	//printk("\n=============tsc2003 read================\n");
	TS_RET ts_ret;

retry: 
	if (tsdev.head != tsdev.tail) {
		int count;
		count = tsRead(&ts_ret);
		if (count) copy_to_user(buffer, (char *)&ts_ret, count);
		return count;
	} else {
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;	
	interruptible_sleep_on(&(tsdev.wq));
		if (signal_pending(current))
			return -ERESTARTSYS;
			
 		goto retry;
	}
			
	return sizeof(TS_RET);
}

static int pm3210_ts_open(struct inode *inode, struct file *filp)
{

	//printk("\n=============tsc2003 open================\n");

	tsdev.head = tsdev.tail = 0;
	tsdev.penStatus = PEN_UP;
	init_timer(&ts_timer);
	ts_timer.function = ts_timer_handler;
	//    hardware initalize
	init_waitqueue_head(&(tsdev.wq));
	return 0;
}

static unsigned int pm3210_ts_poll(struct file *filp,struct poll_table_struct *wait)
{
	poll_wait(filp,&(tsdev.wq),wait);
	return (tsdev.head==tsdev.tail)?0:(POLLIN|POLLRDNORM);
}

#ifdef USE_ASYNC
static int pm3210_ts_fasync(int fd,struct file *filp,int mode)
{
	return fasync_helper(fd,filp,mode,&(tsdev.aq));
}

#endif
static int pm3210_ts_release(struct inode *inode,struct file *filp)
{
	del_timer(&ts_timer);
	return 0;
	
}
static struct file_operations pm3210_fops = {
	owner:	THIS_MODULE,
	open:	pm3210_ts_open,
	read:	pm3210_ts_read,
	poll:   pm3210_ts_poll,
	release:pm3210_ts_release,
#ifdef USE_ASYNC
	fasync:pm3210_ts_fasync,
#endif

};

static irqreturn_t tsc2003_pen_isr(int irq,void *dev_id,struct pt_regs *regs)
{
	//printk("irq\n");
	if(IsPen_down())
	{
	
	tsdev.penStatus = PEN_DOWN;
	*INT_POL |= (1<<INT_EDGE_GPIO13);//high voltage triggle
	//printk("irq down =0x%0x\n",*INT_POL);

		if(atomic_read(&timer_sw) == 0)
		{
			atomic_set(&timer_sw , 1);
		 	ts_timer.expires = jiffies + TS_TIMER_DELAY;
		  	add_timer(&ts_timer);
		}
	}	
	else 
	{
	
	*INT_POL &= ~(1<<INT_EDGE_GPIO13);//low voltage triggle
	//printk("irq up =0x%0x\n",*INT_POL);

	}
	
        return IRQ_HANDLED;
	
}
static void tsc2003_setup_cdev()
    {
        int err;
	int tsc2003_devno = MKDEV(tsc2003_major,0);
        cdev_init(&tsc2003_cdev,&pm3210_fops);
        tsc2003_cdev.owner = THIS_MODULE;
        tsc2003_cdev.ops = &pm3210_fops;
        err = cdev_add(&tsc2003_cdev,tsc2003_devno,1);

        if(err)
        {
            printk(KERN_NOTICE "Error %d adding tsc2003",err);
        }
    }

static int __init pm3210_ts_init(void)
{
	int ret;

	*GPIO_OE_15_8 &= (unsigned char) ~(1<<5);//GPIO13 output disable 
	
	*INT_POL &= ~(1<<INT_EDGE_GPIO13);//low voltage to triggle the interrupt
	

	*INT_EN |=1<<INT_EDGE_GPIO13;
	myi2c_write(RESERV_CMD,1);

	atomic_set(&timer_sw,0);
	init_MUTEX(&tsdev.sem);

	ret=request_irq(INT_EDGE_GPIO13,tsc2003_pen_isr,SA_INTERRUPT,DEVICE_NAME,tsc2003_pen_isr);

	/* Get irqs */
	if (ret) {
		printk(KERN_ERR "TSC2003_ts.c: Could not allocate ts INT_EDGE_GPIO13 !\n");
		goto tc_failed;
	}

	printk("DEVICE_NAME  initialized\n");
	 int register_result=0;
        dev_t tsc2003_devno = MKDEV(tsc2003_major,0);
        printk("\ntsc2003 driver\n");
//begin applying for the device number for registration
        if(tsc2003_major)
        {
            register_result = register_chrdev_region(tsc2003_devno,1,DEVICE_NAME);
        }
        else
        {
            register_result = alloc_chrdev_region(&tsc2003_devno,0,1,DEVICE_NAME);
            tsc2003_major = MAJOR(tsc2003_devno);
        }

        if(register_result < 0)
        {
            return register_result;
        }
//begin registering
        tsc2003_setup_cdev();
	return 0;
 tc_failed:
	free_irq(INT_EDGE_GPIO13, tsc2003_pen_isr);
	return ret;
}

static void __exit pm3210_ts_exit(void)
{

	cdev_del(&tsc2003_cdev);
	printk("tsc2003 exit\n");
        unregister_chrdev_region(MKDEV(tsc2003_major,0),1);
	free_irq(INT_EDGE_GPIO13, tsc2003_pen_isr);
}
module_init(pm3210_ts_init);
module_exit(pm3210_ts_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -