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

📄 s3c2410_ts.c

📁 FS2410开发板点触屏驱动原码
💻 C
字号:
 /* * drivers/char/s3c2410-ts.c * * touchScreen driver for SAMSUNG S3C2410 *  */#include <linux/config.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/coda.h>#include <linux/cdev.h>#include <linux/interrupt.h>#include <linux/devfs_fs_kernel.h>#include <asm/io.h>#include <asm/hardware/clock.h>#include <asm/arch/regs-adc.h>#include <asm/arch/regs-gpio.h>#include <asm/irq.h>#include <linux/delay.h>#include <asm/hardware.h>/* debug macros */#undef DEBUG#ifdef DEBUG#define DPRINTK( x... )	printk("s3c2410-ts: " ##x)#else#define DPRINTK( x... )#endif#define PEN_UP	        0		#define PEN_DOWN	1#define PEN_FLEETING	2#define MAX_TS_BUF	8	/* how many do we want to buffer */#define DEVICE_NAME	"s3c2410-ts"static struct cdev ts = {        .kobj   =       {.name = "ts", },        .owner  =       THIS_MODULE,};typedef struct {  unsigned short pressure;  unsigned short x;  unsigned short y;  unsigned short pad;} TS_RET;typedef struct {	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;	spinlock_t lock;	struct fasync_struct *aq;} TS_DEV;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))unsigned long tmp;dev_t chrdev;static void (*tsEvent)(void);#define TS_TIMER_DELAY  (HZ/100) /* 10 ms */static struct timer_list ts_timer;#define wait_down_int()	{ S3C2410_DOWN_INT | S3C2410_ADCTSC_XP_PULL_UP_EN | \		          S3C2410_ADCTSC_XP_AIN | S3C2410_ADCTSC_XM_HIZ | \                          S3C2410_ADCTSC_YP_AIN | S3C2410_ADCTSC_YM_GND | \		          S3C2410_ADCTSC_XY_PST(S3C2410_WAIT_INT_MODE); }#define wait_up_int()	{ S3C2410_UP_INT | S3C2410_ADCTSC_XP_PULL_UP_EN | \                          S3C2410_ADCTSC_XP_AIN | S3C2410_ADCTSC_XM_HIZ | \		          S3C2410_ADCTSC_YP_AIN | S3C2410_ADCTSC_YM_GND | \                          S3C2410_ADCTSC_XY_PST(S3C2410_WAIT_INT_MODE); }#define mode_x_axis()	{ S3C2410_ADCTSC_XP_EXTVLT | S3C2410_ADCTSC_XM_GND | \                          S3C2410_ADCTSC_YP_AIN | S3C2410_ADCTSC_YM_HIZ | \			  S3C2410_ADCTSC_XP_PULL_UP_DIS | \                          S3C2410_ADCTSC_XY_PST(S3C2410_X_AXIS_MODE); }#define mode_y_axis()	{ S3C2410_ADCTSC_XP_AIN | S3C2410_ADCTSC_XM_HIZ | \                          S3C2410_ADCTSC_YP_EXTVLT | S3C2410_ADCTSC_YM_GND | \                     	  S3C2410_ADCTSC_XP_PULL_UP_DIS | \                          S3C2410_ADCTSC_XY_PST(S3C2410_Y_AXIS_MODE); }#define start_adc_x()	{ S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(49) | \			  S3C2410_ADCCON_SELMUX(S3C2410_ADC_IN5) | \                          S3C2410_ADCCON_READ_START; }#define start_adc_y()	{ S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(49) | \			  S3C2410_ADCCON_SELMUX(S3C2410_ADC_IN7) | \                          S3C2410_ADCCON_READ_START; } static int adc_state = 0;static int x, y;//touch screen coorinatesstatic void __iomem *base_addr;static void tsEvent_raw(void){	if (tsdev.penStatus == PEN_DOWN) {		BUF_HEAD.x = x;		BUF_HEAD.y = y;		BUF_HEAD.pressure = PEN_DOWN;		ts_timer.expires = jiffies + TS_TIMER_DELAY;		add_timer(&ts_timer);	} else {		del_timer(&ts_timer);				BUF_HEAD.x = 0;		BUF_HEAD.y = 0;		BUF_HEAD.pressure = PEN_UP;	}	tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);	wake_up_interruptible(&(tsdev.wq));	if (tsdev.aq)		kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);}static int tsRead(TS_RET * ts_ret){  spin_lock_irq(&(tsdev.lock));	ts_ret->x = BUF_TAIL.x;	ts_ret->y = BUF_TAIL.y;	ts_ret->pressure = BUF_TAIL.pressure;	tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);	spin_unlock_irq(&(tsdev.lock));        	return sizeof(TS_RET);}static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){	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 s3c2410_ts_fasync(int fd, struct file *filp, int mode) {	return fasync_helper(fd, filp, mode, &(tsdev.aq));}static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait){	poll_wait(filp, &(tsdev.wq), wait);	return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM); }static inline void start_ts_adc(void){	adc_state = 0;  writel(mode_x_axis(), base_addr+S3C2410_ADCTSC); //mode_x_axis();  writel(start_adc_x(), base_addr+S3C2410_ADCCON); //	start_adc_x();  tmp=readl(base_addr+S3C2410_ADCCON);  tmp &=~(S3C2410_ADCCON_STDBM);  writel(tmp, base_addr+S3C2410_ADCCON);  readl(base_addr+S3C2410_ADCDAT0);}static inline void s3c2410_get_XY(void){	if (adc_state == 0) { 		adc_state = 1;	  tmp = readl(base_addr+S3C2410_ADCCON);	  tmp &= ~(S3C2410_ADCCON_READ_START);	  writel(tmp, base_addr+S3C2410_ADCCON); // disable_ts_adc();	  y = (readl(base_addr+S3C2410_ADCDAT0) & 0x3ff); // y = (ADCDAT0 & 0x3ff); 	  writel(mode_y_axis(), base_addr+S3C2410_ADCTSC);// mode_y_axis();	  writel(start_adc_y(), base_addr+S3C2410_ADCCON);//	start_adc_y();	  tmp=readl(base_addr+S3C2410_ADCCON);	  tmp &=~(S3C2410_ADCCON_STDBM);	  writel(tmp, base_addr+S3C2410_ADCCON);	  readl(base_addr+S3C2410_ADCDAT1);	}         else if (adc_state == 1) { 		adc_state = 0;    tmp = readl(base_addr+S3C2410_ADCCON);    tmp &= ~(S3C2410_ADCCON_READ_START);    writel(tmp, base_addr+S3C2410_ADCCON); //	disable_ts_adc();     x = (readl(base_addr+S3C2410_ADCDAT1) & 0x3ff); //	x = (ADCDAT1 & 0x3ff);		tsdev.penStatus = PEN_DOWN;		DPRINTK("PEN DOWN: x: %08d, y: %08d\n", x, y);                writel(wait_up_int(), base_addr+S3C2410_ADCTSC);//	wait_up_int();		tsEvent();	}}static irqreturn_t s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg){	spin_lock_irq(&(tsdev.lock));	s3c2410_get_XY();	spin_unlock_irq(&(tsdev.lock));  return IRQ_HANDLED;}static irqreturn_t s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg){	spin_lock_irq(&(tsdev.lock));	if (tsdev.penStatus == PEN_UP) {	  start_ts_adc();	}         else {	  tsdev.penStatus = PEN_UP;	  DPRINTK("PEN UP: x: %08d, y: %08d\n", x, y);    writel(wait_down_int(), base_addr+S3C2410_ADCTSC);//wait_down_int();	  tsEvent();	}	spin_unlock_irq(&(tsdev.lock));        return IRQ_HANDLED;}static void ts_timer_handler(unsigned long data){	spin_lock_irq(&(tsdev.lock));	if (tsdev.penStatus == PEN_DOWN) {		start_ts_adc();	}	spin_unlock_irq(&(tsdev.lock));}static int s3c2410_ts_open(struct inode *inode, struct file *filp){	tsdev.head = tsdev.tail = 0;	tsdev.penStatus = PEN_UP;	init_timer(&ts_timer);	ts_timer.function = ts_timer_handler;	tsEvent = tsEvent_raw;	init_waitqueue_head(&(tsdev.wq));	return 0;}static int s3c2410_ts_release(struct inode *inode, struct file *filp){	del_timer(&ts_timer);	return 0;}static struct file_operations s3c2410_fops = {	owner:	  THIS_MODULE,	open:	  s3c2410_ts_open,	read:	  s3c2410_ts_read,		release:  s3c2410_ts_release,	fasync:	  s3c2410_ts_fasync,	poll:	  s3c2410_ts_poll,};void tsEvent_dummy(void) {}static struct clk       *adc_clock;static int __init s3c2410_ts_probe(struct device *dev){  int ret = 0;	tsEvent = tsEvent_dummy;  adc_clock = clk_get(NULL, "adc");  if (!adc_clock) {      printk(KERN_ERR "failed to get adc clock source\n");      return -ENOENT;  }  clk_use(adc_clock);  clk_enable(adc_clock);  base_addr=ioremap(S3C2410_PA_ADC,0x20);  if (base_addr == NULL) {      printk(KERN_ERR "Failed to remap register block\n");      return -ENOMEM;  }  if(alloc_chrdev_region(&chrdev,0,1,"ts")){      printk(KERN_ERR"Couldn't alloc chrdev region\n");      return 1;  }  cdev_init(&ts,&s3c2410_fops);  if(cdev_add(&ts, chrdev, 1)){    unregister_chrdev_region(chrdev,1);    printk(KERN_ERR"Couldn't register ts driver\n");    return 1;  }  s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);  s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);  s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);  s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);  if (request_irq(IRQ_ADC, s3c2410_isr_adc, SA_SAMPLE_RANDOM,          "s3c2410_action", &chrdev)) {          printk(KERN_ERR "Could not allocate ts IRQ_ADC !\n");          iounmap(base_addr);          return -EIO;  }  if (request_irq(IRQ_TC, s3c2410_isr_tc, SA_SAMPLE_RANDOM,                  "s3c2410_action", &chrdev)) {          printk(KERN_ERR "Could not allocate ts IRQ_TC !\n");          iounmap(base_addr);          free_irq(IRQ_ADC,&chrdev);          return -EIO;  }  writel(wait_down_int(), base_addr+S3C2410_ADCTSC);//wait_down_int();  ret = devfs_mk_cdev(chrdev,S_IFCHR | S_IRUGO | S_IWUSR, DEVICE_NAME);  if(ret)      goto out_chrdev;	writel(0xFFFF, base_addr+S3C2410_ADCDLY);  printk(KERN_INFO "Tochu screen successfully loaded\n");	goto out;out_chrdev:        unregister_chrdev(chrdev, DEVICE_NAME);out:        return ret;}static int s3c2410_ts_remove(struct device *dev){	unregister_chrdev(chrdev, DEVICE_NAME);  disable_irq(IRQ_ADC);  disable_irq(IRQ_TC);  free_irq(IRQ_TC,&chrdev);  free_irq(IRQ_ADC,&chrdev);  if (adc_clock) {      clk_disable(adc_clock);      clk_unuse(adc_clock);      clk_put(adc_clock);      adc_clock = NULL;  }  iounmap(base_addr);  return 0;}static struct device_driver s3c2410_ts_driver = { .name           = DEVICE_NAME, .bus            = &platform_bus_type, .probe          = s3c2410_ts_probe, .remove         = s3c2410_ts_remove,};int __init s3c2410_ts_init(void){   return driver_register(&s3c2410_ts_driver);}void __exit s3c2410_ts_exit(void){  driver_unregister(&s3c2410_ts_driver);}module_init(s3c2410_ts_init);module_exit(s3c2410_ts_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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