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

📄 ads7843.c

📁 本程序是在ARM9200上实现对四线触摸屏的控制芯片ad7843的驱动
💻 C
字号:
/* *  linux/drivers/misc/ads7843-ts.c * *  Copyright (C) 2001 Russell King, All Rights Reserved. * * 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. * * 21-Jan-2002 <jco@ict.es> : * * Added support for synchronous A/D mode. This mode is useful to * avoid noise induced in the touchpanel by the LCD, provided that * the ads7843 has a valid LCD sync signal routed to its ADCSYNC pin. * It is important to note that the signal connected to the ADCSYNC * pin should provide pulses even when the LCD is blanked, otherwise * a pen touch needed to unblank the LCD will never be read. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/completion.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/pm.h>#include <linux/miscdevice.h>#include <linux/poll.h>#include <asm/dma.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <asm/hardware.h>#include "ads7843.h"/* *  Hardware Pins */#define TS_CLK	   AT91C_PIO_PD1#define TS_CS	   AT91C_PIO_PD5#define TS_DIN	   AT91C_PIO_PD2#define TS_DOUT	   AT91C_PIO_PD3/* * This structure is nonsense - millisecs is not very useful * since the field size is too small.  Also, we SHOULD NOT * be exposing jiffies to user space directly. */struct ts_event 			{			u16		pressure;			u16		x;			u16		y;			u16		pad;			struct timeval	stamp;			};#define NR_EVENTS	16struct ads7843_ts 			{			//	int			ads7843_fd;				wait_queue_head_t	irq_wait;			struct semaphore	sem;			struct completion	init_exit;			struct task_struct	*rtask;			int			use_count;			struct fasync_struct	*fasync;			wait_queue_head_t	read_wait;			u8			evt_head;			u8			evt_tail;			struct ts_event		events[NR_EVENTS];				int			restart:1;			};static struct ads7843_ts spi_ts;static int ads7843_ts_startup(struct ads7843_ts *ts);static void ads7843_ts_shutdown(struct ads7843_ts *ts);static void ads7843_ts_irq(int, int, void *);#define ads7843_ts_evt_pending(ts)	((volatile u8)(ts)->evt_head != (ts)->evt_tail)#define ads7843_ts_evt_get(ts)		((ts)->events + (ts)->evt_tail)#define ads7843_ts_evt_pull(ts)		((ts)->evt_tail = ((ts)->evt_tail + 1) & (NR_EVENTS - 1))#define ads7843_ts_evt_clear(ts)	((ts)->evt_head = (ts)->evt_tail = 0)static unsigned short ads7843_transfer(unsigned char cmd){	int i;	unsigned char bit;	unsigned short read_data = 0;		/* CS# Low */	AT91_SYS->PIOD_CODR = TS_CS;	udelay(10);		/* Transform CMD */	for(i=1; i<=8; i++){		/* CMD Output */		bit = ( cmd >> (8-i) ) & 0x01 ;		if( bit )			AT91_SYS->PIOD_SODR = TS_DIN;	        else			AT91_SYS->PIOD_CODR = TS_DIN;		udelay(5);						/* CLK High */		AT91_SYS->PIOD_SODR = TS_CLK;		udelay(10);		/* CLK Low */		AT91_SYS->PIOD_CODR = TS_CLK;		udelay(5);	}		/* Waiting for busy */	udelay(20);		/* Read DATA */	for(i=7; i>=0; i--){		/* CLK High */		AT91_SYS->PIOD_SODR = TS_CLK;		udelay(10);		/* CLK Low */		AT91_SYS->PIOD_CODR = TS_CLK;				/* Data in */		if( (AT91_SYS->PIOD_PDSR & TS_DOUT) != 0 )			read_data |= 1 << i;		udelay(10);	}		/* CS# High */	AT91_SYS->PIOD_SODR = TS_CS;	udelay(50);	return read_data;}static inline void ads7843_ts_evt_add(struct ads7843_ts *ts, u16 pressure, u16 x, u16 y){		int next_head;		next_head = (ts->evt_head + 1) & (NR_EVENTS - 1);		if (next_head != ts->evt_tail) 				{				ts->events[ts->evt_head].pressure = pressure;				ts->events[ts->evt_head].x = x;				ts->events[ts->evt_head].y = y;				do_gettimeofday(&ts->events[ts->evt_head].stamp);				ts->evt_head = next_head;				if (ts->fasync)						kill_fasync(&ts->fasync, SIGIO, POLL_IN);				wake_up_interruptible(&ts->read_wait);				}}static inline void ads7843_ts_event_release(struct ads7843_ts *ts){	ads7843_ts_evt_add(ts, 0, 0, 0);}/* * User space driver interface. */static ssize_tads7843_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){		DECLARE_WAITQUEUE(wait, current);		struct ads7843_ts *ts = filp->private_data;		char *ptr = buffer;		int err = 0;		add_wait_queue(&ts->read_wait, &wait);		while (count >= sizeof(struct ts_event)) 				{				err = -ERESTARTSYS;				if (signal_pending(current))						break;				if (ads7843_ts_evt_pending(ts)) 						{						struct ts_event *evt = ads7843_ts_evt_get(ts);						err = copy_to_user(ptr, evt, sizeof(struct ts_event));						ads7843_ts_evt_pull(ts);						if (err)								break;						ptr += sizeof(struct ts_event);						count -= sizeof(struct ts_event);						continue;						}				set_current_state(TASK_INTERRUPTIBLE);				err = -EAGAIN;				if (filp->f_flags & O_NONBLOCK)						break;				schedule();				}		current->state = TASK_RUNNING;		remove_wait_queue(&ts->read_wait, &wait); 		return ptr == buffer ? err : ptr - buffer;}static unsigned int ads7843_ts_poll(struct file *filp, poll_table *wait){	struct ads7843_ts *ts = filp->private_data;	int ret = 0;	poll_wait(filp, &ts->read_wait, wait);	if (ads7843_ts_evt_pending(ts))		ret = POLLIN | POLLRDNORM;	return ret;}static int ads7843_ts_fasync(int fd, struct file *filp, int on){	struct ads7843_ts *ts = filp->private_data;	return fasync_helper(fd, filp, on, &ts->fasync);}static int ads7843_ts_open(struct inode *inode, struct file *filp){	struct ads7843_ts *ts = &spi_ts;	int ret = 0;	ret = ads7843_ts_startup(ts);	if (ret == 0)		filp->private_data = ts;	return ret;}/* * Release touchscreen resources.  Disable IRQs. */static int ads7843_ts_release(struct inode *inode, struct file *filp){	struct ads7843_ts *ts = filp->private_data;	down(&ts->sem);	ads7843_ts_fasync(-1, filp, 0);	ads7843_ts_shutdown(ts);	up(&ts->sem);	return 0;}static struct file_operations ads7843_fops = {	owner:		THIS_MODULE,	read:		ads7843_ts_read,	poll:		ads7843_ts_poll,	open:		ads7843_ts_open,	release:	ads7843_ts_release,	fasync:		ads7843_ts_fasync,};/* * The official ads7843 touchscreen is a miscdevice: *   10 char        Non-serial mice, misc features *                   14 = /dev/touchscreen/ads7843  touchscreen */static struct miscdevice ads7843_ts_dev = {	minor:	14,	name:	"touchscreen",	fops:	&ads7843_fops,};static inline int ads7843_ts_register(struct ads7843_ts *ts){	init_waitqueue_head(&ts->read_wait);	return misc_register(&ads7843_ts_dev);}static inline void ads7843_ts_deregister(struct ads7843_ts *ts){	misc_deregister(&ads7843_ts_dev);}/* * Switch to X position mode and measure Y plate.  We switch the plate * configuration in pressure mode, then switch to position mode.  This * gives a faster response time.  Even so, we need to wait about 55us * for things to stabilise. */static void ads7843_ts_read_pos(struct ads7843_ts *ts, struct ts_event *event){	int i;	unsigned char cmd[2];	unsigned short data[2];		cmd[0] = MEASURE_8BIT_X;	cmd[1] = MEASURE_8BIT_Y;		for(i=0; i<2; i++){		data[i] = ads7843_transfer(cmd[i]);	}		event->x = data[0];	event->y = data[1];	event->pressure = 100;	printk("read pos: x = %x, y = %x\n", event->x, event->y);}/* * This is a RT kernel thread that handles the ADC accesses. */static int ads7843_thread(void *ptr){	struct ads7843_ts *ts = ptr;	struct task_struct *tsk = current;	DECLARE_WAITQUEUE(wait, tsk);	int valid;	ts->rtask = tsk;	daemonize();	reparent_to_init();	strcpy(tsk->comm, "ktsd");	tsk->tty = NULL;	/*	 * We could run as a real-time thread.  However, thus far	 * this doesn't seem to be necessary.	 *///	tsk->policy = SCHED_FIFO;//	tsk->rt_priority = 1;	/* only want to receive SIGKILL */	spin_lock_irq(&tsk->sigmask_lock);	siginitsetinv(&tsk->blocked, sigmask(SIGKILL));	recalc_sigpending(tsk);	spin_unlock_irq(&tsk->sigmask_lock);	complete(&ts->init_exit);	valid = 0;	add_wait_queue(&ts->irq_wait, &wait);	for (;;) {		struct ts_event event;		unsigned int x, y, p;		unsigned long val;		signed long timeout;		ts->restart = 0;		ads7843_ts_read_pos(ts, &event);		x = event.x;		y = event.y;		p = event.pressure;				set_task_state(tsk, TASK_UNINTERRUPTIBLE);		schedule_timeout(HZ / 100);		if (signal_pending(tsk))			break;		val = AT91_SYS->PIOD_PDSR;		if (val & 0x01) {			set_task_state(tsk, TASK_INTERRUPTIBLE);			AT91_SYS->PIOD_IER = (1 << 0);						/*			 * If we spat out a valid sample set last time,			 * spit out a "pen off" sample here.			 */			if (valid) {				ads7843_ts_event_release(ts);				valid = 0;			}			timeout = MAX_SCHEDULE_TIMEOUT;		} else {			/*			 * Filtering is policy.  Policy belongs in user			 * space.  We therefore leave it to user space			 * to do any filtering they please.			 */			if (!ts->restart) {				ads7843_ts_evt_add(ts, p, x, y);				valid = 1;			}			set_task_state(tsk, TASK_INTERRUPTIBLE);			timeout = HZ / 100;		}		schedule_timeout(timeout);		if (signal_pending(tsk))			break;	}	remove_wait_queue(&ts->irq_wait, &wait);	ts->rtask = NULL;	ads7843_ts_evt_clear(ts);	complete_and_exit(&ts->init_exit, 0);}/* * We only detect touch screen _touches_ with this interrupt * handler, and even then we just schedule our task. */static void ads7843_ts_irq(int pio, int pin, void *id){	struct ads7843_ts *ts = id;	/* Disable ts interrupt */	AT91_SYS->PIOD_IDR = (1 << 0);	wake_up(&ts->irq_wait);}static int ads7843_ts_startup(struct ads7843_ts *ts){	int ret = 0;	if (down_interruptible(&ts->sem))		return -EINTR;		if (ts->use_count++ != 0)		goto out;		if (ts->rtask)		panic("ads7843: rtask running?");		init_waitqueue_head(&ts->irq_wait);	ret = at91rm9200_gpio_request_irq(AT91C_ID_PIOD, 0, 0, ads7843_ts_irq, ts);	if (ret < 0) {		goto out;	}		init_completion(&ts->init_exit);	ret = kernel_thread(ads7843_thread, ts, 0);	if (ret >= 0) {		wait_for_completion(&ts->init_exit);		ret = 0;		up(&ts->sem);		return ret;	} else {		at91rm9200_gpio_free_irq(AT91C_ID_PIOD, 0, ts);	} out:	printk("out\n");	if (ret)		ts->use_count--;	up(&ts->sem);	return ret;}/* * Release touchscreen resources.  Disable IRQs. */static void ads7843_ts_shutdown(struct ads7843_ts *ts){	if (--ts->use_count == 0) {		if (ts->rtask) {			send_sig(SIGKILL, ts->rtask, 1);			wait_for_completion(&ts->init_exit);		}				at91rm9200_gpio_free_irq(AT91C_ID_PIOD, 0, ts);	}}/* * Initialisation. */static int __init ads7843_ts_init(void){	struct ads7843_ts *ts = &spi_ts;	printk("Driver for ADS7843 Load\n");		/* hardware init */	AT91_SYS->PIOD_PER = TS_CS | TS_CLK | TS_DIN | TS_DOUT;	AT91_SYS->PIOD_OER = TS_CS | TS_CLK | TS_DIN;	AT91_SYS->PIOD_ODR = TS_DOUT;		AT91_SYS->PIOD_SODR = TS_CS;	AT91_SYS->PIOD_CODR = TS_CLK | TS_DIN;		AT91_SYS->PIOD_PER = AT91C_PIO_PD0 | AT91C_PIO_PD4;	AT91_SYS->PIOD_ODR = AT91C_PIO_PD0 | AT91C_PIO_PD4;		init_MUTEX(&ts->sem);		return ads7843_ts_register(ts);}static void __exit ads7843_ts_exit(void){	struct ads7843_ts *ts = &spi_ts;	ads7843_ts_deregister(ts);}module_init(ads7843_ts_init);module_exit(ads7843_ts_exit);MODULE_AUTHOR("Bears H <yellowyel@arm.linux.org.uk>");MODULE_DESCRIPTION("ads7843 touchscreen driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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