触模屏设备驱动
来源:互联网 发布:lcd1602编程 编辑:程序博客网 时间:2024/06/05 16:10
/*=========================================================================
工程名称: 4_touchscreen_driver
组成文件: touch_driver.c
功能描述: 触模屏设备驱动,可以返回坐标或AD值
硬件连接: 连接四线电阻式触模屏
=========================================================================*/
#include <linux/module.h> /*module_init()*/
#include <linux/kernel.h> /* printk() */
#include <linux/init.h> /* __init __exit */
#include <linux/fs.h> /* file_operation */
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */
#include <linux/device.h> /*class ,class_create ,device_create 等*/
#include <linux/errno.h> /* Error number */
#include <linux/delay.h> /* mdelay ,ndelay*/
#include <asm/delay.h> /* udelay */
#include <mach/regs-gpio.h> /*S3C2410_GPGCON*/
#include <linux/pci.h> /*S3C24XX_VA_GPIO*/
#include <linux/irq.h> //set_irq_type ,IRQ_TYPE_EDGE_FALLING
#include <linux/interrupt.h> //request_irq , free_irq
#include <plat/regs-adc.h> // S3C2410_ADCCON
#include <asm/io.h> //ioremap()
#include <linux/clk.h> //clk_get() , clk_enable()
//#define DEBUG //open debug message
#ifdef DEBUG
#define PRINTK(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#else
#define PRINTK(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
#endif
#define ADCCON (*(volatile unsigned long *)(regs_adc + S3C2410_ADCCON))//ADC control
#define ADCDLY (*(volatile unsigned long *)(regs_adc + S3C2410_ADCDLY))//ADC start or Interval Delay
#define ADCDAT0 (*(volatile unsigned long *)(regs_adc + S3C2410_ADCDAT0))
#define ADCDAT1 (*(volatile unsigned long *)(regs_adc + S3C2410_ADCDAT1))
#define ADCTSC (*(volatile unsigned long *)(regs_adc + S3C2410_ADCTSC))
#define TOUCH_WIDTH 320// 触摸屏的水平分辨率
#define TOUCH_HEIGHT240 // 触摸屏的垂直分辨率
#define TOUCH_DEFAULT_LB 0x55// 左边缘对应的默认AD转换值(16bit)
#define TOUCH_DEFAULT_RB 0x3ac// 右边缘对应的默认AD转换值(16bit)
#define TOUCH_DEFAULT_TB 0x89// 上边缘对应的默认AD转换值(16bit)
#define TOUCH_DEFAULT_BB 0x384// 下边缘对应的默认AD转换值(16bit)
#define PEN_UP 0
#define PEN_DOWN 1
#define PEN_FLEETING 2
#define MAX_TS_BUF 16/* how many do we want to buffer */
#define ADC_X_END 0
#define ADC_Y_END 1
#define DRIVER_NAME "touch_driver"
#define TSRAW_MINOR 1
#define BUF_HEAD (tsdev.buf[tsdev.head])
#define BUF_TAIL (tsdev.buf[tsdev.tail])
#define INCBUF(x,mod) ((++(x)) & ((mod) - 1))
#define ADC_FREQ 2000000 // 2MHz AD convert freq 030918
static void __iomem *regs_adc;
static int PreScale_n = 30; // PCLK / (PreScale_n+1) = ADConversion freq.
//以struct TS_RET结构体的形式给应用层转递数据
struct TS_RET{
unsigned short pressure;
unsigned short x;
unsigned short y;
unsigned short pad;
};
typedef struct
{
unsigned int penStatus;/* PEN_UP, PEN_DOWN, PEN_SAMPLE */
struct TS_RET buf[MAX_TS_BUF];/* protect against overrun */
unsigned int head, tail;/* head and tail for queued events */
} TS_DEV;
static int MAJOR_NR = 0;
static int MINOR_NR = 0;
struct class *my_class;
static TS_DEV tsdev;
static int adc_state = ADC_X_END;
static int p_x,p_y; //通过这两个全局变量来保存AD值
static void tsEvent_raw(void)
{
if (tsdev.penStatus == PEN_DOWN)
{
#if 0
//x,y从右上AD 值最小,左下最大,但坐标从左上最小开始
BUF_HEAD.x = TOUCH_WIDTH * ( TOUCH_DEFAULT_RB -p_x) / (TOUCH_DEFAULT_RB - TOUCH_DEFAULT_LB);
BUF_HEAD.y = TOUCH_HEIGHT * (p_y - TOUCH_DEFAULT_TB) / (TOUCH_DEFAULT_BB - TOUCH_DEFAULT_TB);
#else
BUF_HEAD.x = p_x;
BUF_HEAD.y = p_y;
#endif
BUF_HEAD.pressure = PEN_DOWN;
}
else
{
BUF_HEAD.x = 0;
BUF_HEAD.y = 0;
BUF_HEAD.pressure = PEN_UP;
}
tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);
}
//从消息队列读取坐标值
static int tsRead(struct TS_RET * ts_ret)
{
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);
return sizeof(struct TS_RET);
}
static ssize_t s3c2440_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
struct TS_RET ts_ret;
int ret;
//读取不阻塞
if (tsdev.head != tsdev.tail)
{
ret = tsRead(&ts_ret);
if (ret)
ret = copy_to_user(buffer, (char *)&ts_ret, ret);
return ret;
}
else
return -1;
}
static inline void start_ts_adc(void)
{
int read_ad;
ADCTSC = (1<<6)|(1<<5)|(1<<3)|(1); //读取x模式
ADCCON = (1<<14)|(PreScale_n<<6)|(5<<3)|(1<<1)|(1);//设置频率启动AD
read_ad = ADCDAT0;//启动AD转换
adc_state = ADC_X_END; //设置转换状态
}
//通过AD转换结束中断回调该函数,最后计算并将点击坐标放入消息队列
static inline void s3c2440_get_XY(void)
{
int read_ad;
if (adc_state == ADC_X_END)
{
ADCCON &= ~(1<<1);//禁止读取转换
p_x = (ADCDAT0 & 0x3ff);
ADCTSC = (1<<7)|(1<<4)|(1<<3)|(2);//读y模式
ADCCON = (1<<14)|(PreScale_n<<6)|(7<<3)|(1<<1)|(1);//设置频率启动AD
read_ad = ADCDAT1;
adc_state = ADC_Y_END;
}
else if (adc_state == ADC_Y_END)
{
ADCCON &= ~(1<<1);//禁止读取转换
p_y = (ADCDAT1 & 0x3ff);
tsdev.penStatus = PEN_DOWN;
PRINTK("PEN DOWN: x: %08d, y: %08d\n", p_x, p_y);
ADCTSC = (1<<8)|(1<<7)|(1<<6)|(1<<4)|(3);//等待UP 中断模式
tsEvent_raw();
adc_state = ADC_X_END;
}
}
static irqreturn_t s3c2440_isr_adc(int irq, void *dev_id)
{
if (tsdev.penStatus == PEN_UP)
{
s3c2440_get_XY();
}
return 0;
}
static irqreturn_t s3c2440_isr_tc(int irq, void *dev_id)
{
PRINTK("\ns3c2440_isr_tc!!!\n");
if (tsdev.penStatus == PEN_UP)
{
start_ts_adc();
}
else
{
tsdev.penStatus = PEN_UP;
PRINTK("PEN UP: x: %08d, y: %08d\n", p_x, p_y);
ADCTSC = (1<<4)|(1<<7)|(1<<6)|(3);//等待DOWN 中断模式
}
return 0;
}
static int s3c2440_ts_open(struct inode *inode, struct file *filp)
{
int err;
struct clk *adc_clk;
PRINTK("\ns3c2440_ts_open!!!\n");
adc_clk = clk_get(NULL, "adc");
if(!adc_clk)
{
/*错误处理*/
PRINTK("falied to find adc clock source\n");
clk_disable(adc_clk);
clk_put(adc_clk);
return -ENOENT;
}
clk_enable(adc_clk);
regs_adc = ioremap(S3C2410_PA_ADC, 0x20);
ADCDLY = 20000; // it is got from test
ADCTSC = 0x00;
ADCTSC = (1<<4)|(1<<7)|(1<<6)|(3);//等待DOWN 中断模式
err = request_irq(IRQ_ADC,s3c2440_isr_adc,IRQF_SHARED,"ts_adc", (void *)1);
if(err)
{
PRINTK("IRQ%d error %d\n", IRQ_ADC, err);
free_irq(IRQ_ADC, (void *)1);
iounmap(regs_adc);
err = -EINVAL;
}
err = request_irq(IRQ_TC,s3c2440_isr_tc,IRQF_SHARED,"ts_tc", (void *)2);
if(err)
{
PRINTK("IRQ%d error %d\n", IRQ_TC, err);
free_irq(IRQ_TC, (void *)2);
iounmap(regs_adc);
err = -EINVAL;
}
tsdev.head = tsdev.tail = 0;
tsdev.penStatus = PEN_UP;
return err;
}
static int s3c2440_ts_release(struct inode *inode, struct file *filp)
{
disable_irq(IRQ_ADC);
disable_irq(IRQ_TC);
free_irq(IRQ_ADC, (void *)1);
free_irq(IRQ_TC, (void *)2);
iounmap(regs_adc); /*释放虚拟地址映射空间*/
return 0;
}
static struct file_operations s3c2440_fops = {
owner: THIS_MODULE,
open: s3c2440_ts_open,
read: s3c2440_ts_read,
release: s3c2440_ts_release,
};
static int __init s3c2440_ts_init(void)
{
/* Module init code */
PRINTK("TSdriver_init\n");
/* Driver register */
MAJOR_NR = register_chrdev(MAJOR_NR, DRIVER_NAME, &s3c2440_fops);
if(MAJOR_NR < 0)
{
PRINTK("register char device fail!\n");
return MAJOR_NR;
}
my_class=class_create(THIS_MODULE,"udev_touch");
device_create(my_class,NULL, MKDEV(MAJOR_NR, MINOR_NR), NULL,DRIVER_NAME);
PRINTK("register myDriver OK! Major = %d\n", MAJOR_NR);
return 0;
}
static void __exit s3c2440_ts_exit(void)
{
/* Module exit code */
PRINTK("exit in\n");
/* Driver unregister */
if(MAJOR_NR > 0)
{
unregister_chrdev(MAJOR_NR, DRIVER_NAME);
device_destroy(my_class,MKDEV(MAJOR_NR, MINOR_NR));
class_destroy(my_class);
PRINTK("myModule_exit ok\n");
}
return;
}
module_init(s3c2440_ts_init);
module_exit(s3c2440_ts_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiuhai");
- 触模屏设备驱动
- 设备驱动
- 设备驱动
- 设备驱动
- 设备驱动
- 设备驱动
- 总线,设备,设备驱动
- 字符设备驱动--- 设备操作
- 设备模型:总线、驱动、设备
- 设备驱动和设备模型
- Pci设备驱动:设备枚举
- Linux设备驱动之《字符设备驱动》
- linux设备驱动之总线、设备、驱动
- Linux设备驱动入门----I2C设备驱动
- Linux设备驱动入门----USB设备驱动
- 设备驱动之二----字符设备驱动
- Linux 设备驱动--- 混杂设备驱动
- Linux设备驱动,总线,设备,驱动区别
- oracle 10gR2 RAC+ASM恢复到单实例
- 用户管理命令
- ADC 模块
- Flex 页面加载显示自定义进度条
- AndroidGUI01:TextView的常用技巧
- 触模屏设备驱动
- LINUX用户组权限
- mongo数据库的性能问题
- java异常
- 史上最详细的WIN7下WIFI共享上网教程
- linux用户权限的管理
- wamcc:将Prolog编译成C (No.7-5)
- android之组件5
- 第一篇博客:网站中用到的日历