S3C2440驱动篇—触摸屏驱动分析

2024-04-16 08:18

本文主要是介绍S3C2440驱动篇—触摸屏驱动分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

S3C2440触摸屏驱动

一.硬件简介

       S3C2440触摸屏接口与ADC接口集成在一起,触摸屏X、Y坐标所产生的模拟信号通过通道7、5输入,2440提供触摸屏接口有4种处理模式:普通转换模式、分离的X/Y轴坐标转换模式、自动X/Y轴坐标转换模式、等待中断模式。具体参考2440硬件手册16章。

二.驱动实现

       下面是触摸屏驱动源码,其中使用了linux输入子系统input。暂时还没研究这一块,想深入了解可参考相关资料。

   1. #include <linux/errno.h>  2. #include <linux/kernel.h>  3. #include <linux/module.h>  4. #include <linux/slab.h>  5. #include <linux/input.h>  6. #include <linux/init.h>  7. #include <linux/serio.h>  8. #include <linux/delay.h>  9. #include <linux/platform_device.h>  10. #include <linux/clk.h>  11. #include <linux/gpio.h>  12. #include <asm/io.h>  13. #include <asm/irq.h>  14. #include <plat/regs-adc.h>  15. #include <mach/regs-gpio.h>  16.   17. #define S3C2410TSVERSION 0x0101  18. #define DEVICE_NAME "YC2440_TS"  19.   20. //定义一个WAIT4INT宏,该宏将对ADC触摸屏控制寄存器进行操作S3C2410_ADCTSC_YM_SEN这些宏都定义在regs-adc.h中  21. #define WAIT4INT(x) (((x)>>8)|S3C2410_ADCTSC_YM_SEN|S3C2410_ADCTSC_YP_SEN|S3C2410_ADCTSC_XP_SEN|S3C2410_ADCTSC_XY_PST(3))  22. #define AUTOPST (S3C2410_ADCTSC_YM_SEN|S3C2410_ADCTSC_YP_SEN|S3C2410_ADCTSC_XP_SEN|\  23.         S3C2410_ADCTSC_AUTO_PST|S3C2410_ADCTSC_XY_PST(0))  24.   25. static struct input_dev *dev;  //输入设备结构体  26. static long xp;    //记录转换后的X、Y坐标值  27. static long yp;  28. static int count;  29.   30. extern struct semaphore ADC_LOCK;  //在ADC驱动中定义的信号量  31. static int ownADC = 0;  32.   33. static struct clk *adc_clk;  34.   35. static void __iomem *base_addr;  36. //touch_timer_fire函数分三块执行,下面1、2、3分别实现不同功能  37. static void touch_timer_fire(unsigned long data)  38. {        39.     unsigned long data0;  40.     unsigned long data1;  41.     int updown;  42.   43.     data0 = ioread32(base_addr+S3C2410_ADCDAT0);  44.     data1 = ioread32(base_addr+S3C2410_ADCDAT1);  45.        //判断触摸屏是按下、抬起状态  46.     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));  47.          48.     if(updown)                    49.     {  50.         if(count != 0)     //1.如果触摸屏按下,并且ADC已转换,则报告事件、数据  51.         {  52.             long tmp;  53.               54.             tmp = xp;  55.             xp = yp;  56.             yp = tmp;  57.   58.             xp >>= 2;  59.             yp >>= 2;  60.   61. #ifdef CONFIG_TOUCHSCREEN_DEBUG   62.             struct timeval tv;  63.             do_gettimeofday(&tv);  64.             printk(KERN_DEBUG "T:%06d, X:%03d, Y:%03d\n",(int)tv.tv_usec,xp,yp);  65. #endif  66.   67.             input_report_abs(dev,ABS_X,xp);  68.             input_report_abs(dev,ABS_Y,yp);  69.   70.             input_report_key(dev,BTN_TOUCH,1);  71.             input_report_abs(dev,ABS_PRESSURE,1);  72.             input_sync(dev);    //等待接收方受到数据后回复确认,用于同步  73.         }  74.         //2.如果触摸屏按下,并且没有ADC转换,则启动ADC转换  75.         xp = 0;  76.         yp = 0;  77.         count = 0;  78.   79.         iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE|AUTOPST,base_addr+S3C2410_ADCTSC);  80.         iowrite32(ioread32(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_ENABLE_START,base_addr+S3C2410_ADCCON);  81.     }  82.     else    //3.如果触摸屏抬起状态,则报告事件、数据,重置等待按下状态  83.     {  84.         count = 0;  85.   86.         input_report_key(dev,BTN_TOUCH,0);  87.         input_report_abs(dev,ABS_PRESSURE,0);  88.         input_sync(dev);  89.   90.         iowrite32(WAIT4INT(0),base_addr+S3C2410_ADCTSC);    //将触摸屏重新设置为等待中断状态  91.   92.         if(ownADC)        //如果触摸屏抬起,就意味着这一次的操作结束,所以就释放ADC资源的占有  93.         {  94.             printk(KERN_INFO "up\n");  95.             ownADC = 0;  96.             up(&ADC_LOCK);  97.         }  98.     }  99. }  100. //定义并初始化了一个定时器touch_timer,定时器服务程序为touch_timer_fire  101. static struct timer_list touch_timer=TIMER_INITIALIZER(touch_timer_fire,0,0);  102.   103. static irqreturn_t stylus_updown(int irq,void *dev_id)  //触摸屏中断服务程序,触摸屏按下、抬起执行  104. {  105.     unsigned long data0;  106.     unsigned long data1;  107.     int updown;  108.   109.     if(down_trylock(&ADC_LOCK)==0)  110.     {  111.         ownADC = 1;  112.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);  113.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);  114.   115.         updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));  116.   117.         if(updown)  118.         {      //如果触摸屏按下,则执行touch_timer_fire的功能2  119.             printk(KERN_INFO "down\n");  120.             touch_timer_fire(0);      121.         }  122.         else  123.         {      //如果抬起,结束一次操作,释放相应资源  124.             printk(KERN_INFO "up-irq\n");  125.             ownADC = 0;  126.             up(&ADC_LOCK);  127.         }  128.     }  129.     return IRQ_HANDLED;  130. }  131.   132. static irqreturn_t stylus_action(int irq,void *dev_id)    //ADC中断服务程序  133. {  134.     unsigned long data0;  135.     unsigned long data1;  136.       137.     if(ownADC)  138.     {      //读取一次转换值  139.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);  140.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);  141.   142.         xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;  143.         yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;  144.         count++;  145.   146.         if(count<(1<<2)) //如果转换次数小于4次,重启AD转换  147.         {  148.             iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE|AUTOPST,base_addr+S3C2410_ADCTSC);  149.             iowrite32(ioread32(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_ENABLE_START,base_addr+S3C2410_ADCCON);  150.         }  151.         else   //如果转换4次,启动1个时间滴答的定时器,最终调用touch_timer_fire功能1或功能3  152.         {  153.             mod_timer(&touch_timer,jiffies+1);  154.             iowrite32(WAIT4INT(1),base_addr+S3C2410_ADCTSC); //置触摸屏等待抬起中断  155.         }  156.     }  157.   158.     return IRQ_HANDLED;  159. }  160.   161. static int __init s3c2440ts_init(void)  162. {  163.     int ret;      164.   165.     adc_clk = clk_get(NULL,"adc");  166.     if(!adc_clk)  167.     {  168.         printk(KERN_ERR "Failed to get adc clock\n");  169.         return -ENOENT;  170.     }  171.   172.     clk_enable(adc_clk);  173.   174.     base_addr = ioremap(S3C2410_PA_ADC,0x20);  175.     if(base_addr==NULL)  176.     {  177.         printk(KERN_ERR "Failed to remap register\n");  178.         ret = -EINVAL;  179.         goto err_remap;  180.     }  181.     //初始化AD转换参数,置触摸屏等待按下中断  182.     iowrite32(S3C2410_ADCCON_PRSCEN|S3C2410_ADCCON_PRSCVL(0xff),base_addr+S3C2410_ADCCON);  183.     iowrite32(0xffff,base_addr+S3C2410_ADCDLY);  184.     iowrite32(WAIT4INT(0),base_addr+S3C2410_ADCTSC);  185.     //输入设备申请空间,位于include/linux/input.h  186.     dev = input_allocate_device();  187.     if(!dev)  188.     {  189.         printk(KERN_ERR "unable to allocate input_dev\n");  190.         ret = -ENOMEM;  191.         goto err_alloc;  192.     }  193.   194.     /*下面初始化输入设备,即给输入设备结构体input_dev的成员设置值。evbit字段用于描述支持的事件, 195.       这里支持同步事件、按键事件、绝对坐标事件,BIT宏实际就是对1进行位操作,定义在linux/bitops.h中*/  196.     dev->evbit[0] = BIT(EV_SYN)|BIT(EV_KEY)|BIT(EV_ABS);  197.     /*keybit字段用于描述按键的类型,在input.h中定义了很多,这里用BTN_TOUCH类型来表示触摸屏的点击*/  198.     dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);  199.     /*对于触摸屏来说,使用的是绝对坐标系统。这里设置该坐标系统中X和Y坐标的最小值和最大值(0-1023范围) 200.          ABS_X和ABS_Y就表示X坐标和Y坐标,ABS_PRESSURE就表示触摸屏是按下还是抬起状态*/  201.     input_set_abs_params(dev,ABS_X,0,0x3ff,0,0);  202.     input_set_abs_params(dev,ABS_Y,0,0x3ff,0,0);  203.     input_set_abs_params(dev,ABS_PRESSURE,0,1,0,0);  204.   205.     dev->name = DEVICE_NAME;             /*设备名称*/  206.     dev->id.bustype = BUS_RS232;         /*总线类型*/  207.     dev->id.vendor = 0xDEAD;             /*经销商ID号*/  208.     dev->id.product = 0xBEEF;            /*产品ID号*/  209.     dev->id.version = S3C2410TSVERSION;  /*版本ID号*/  210.   211.     //申请中断,IRQ_ADC为AD、触摸屏共享  212.     ret = request_irq(IRQ_ADC,stylus_action,IRQF_SHARED|IRQF_SAMPLE_RANDOM,DEVICE_NAME,dev);  213.     if(ret)  214.     {  215.         printk(KERN_ERR "request IRQ_ADC fail\n");  216.         ret = -EINVAL;  217.         goto err_alloc;  218.     }  219.   220.     ret = request_irq(IRQ_TC,stylus_updown,IRQF_SAMPLE_RANDOM,DEVICE_NAME,dev);  221.     if(ret)  222.     {  223.         printk(KERN_ERR "requers IRQ_TS fail\n");  224.         ret = -EINVAL;  225.         goto err_adcirq;  226.     }  227.   228.     printk(KERN_INFO "%s successfully load\n",DEVICE_NAME);  229.   230.     /*把dev触摸屏设备注册到输入子系统中*/  231.     input_register_device(dev);  232.     return 0;  233.   234.   235.   236. err_adcirq:  237.     free_irq(IRQ_ADC,dev);  238.   239. err_alloc:  240.     iounmap(base_addr);  241.   242. err_remap:  243.     clk_disable(adc_clk);  244.     clk_put(adc_clk);  245.       246.     return ret;  247. }  248.   249. static void __exit s3c2440ts_exit(void)  250. {  251.     disable_irq(IRQ_ADC);  252.     disable_irq(IRQ_TC);  253.     free_irq(IRQ_ADC,dev);  254.     free_irq(IRQ_TC,dev);  255.   256.     if(adc_clk);  257.     {  258.         clk_disable(adc_clk);  259.         clk_put(adc_clk);  260.         adc_clk = NULL;  261.     }  262.       263.     input_unregister_device(dev);  264.     iounmap(base_addr);  265. }  266.   267. module_init(s3c2440ts_init);  268. module_exit(s3c2440ts_exit);  269.   270. MODULE_LICENSE("GPL");  271. MODULE_AUTHOR("Zechin Liao");  

(1)如果触摸屏感觉到触摸,则触发触摸屏中断即进入stylus_updown,获取ADC_LOCK后判断触摸屏状态为按下,则调用touch_timer_fire启动ADC转换;

(2)当ADC转换启动后,触发ADC中断即进入stylus_action,如果这一次转换的次数小于4,则重新启动ADC进行转换,如果4次完毕后,启动1个时间滴答的定时器,停止ADC转换,也就是说在这个时间滴答内,ADC转换是停止的;

(3)这里为什么要在1个时间滴答到来之前停止ADC的转换呢?这是为了防止屏幕抖动。

(4)如果1个时间滴答到来则进入定时器服务程序touch_timer_fire,判断触摸屏仍然处于按下状态则上报事件和转换的数据,并重启ADC转换,重复第(2)步;

(5)如果触摸抬起了,则上报释放事件,并将触摸屏重新设置为等待中断状态。

 

这里采用动态编译,如果把触摸屏驱动编译进内核,参考ADC驱动。

编辑Makefile:

   1. ifneq ($(KERNELRELEASE),)      2.     obj-m:=s3c2440_ts.o      3. else      4.     KERNELDIR:=/home/liao/image/linux-2.6.32.2      5.     PWD:=$(shell pwd)      6.     all:      7.     make -C $(KERNELDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-      8.     clean:      9.     rm -rf *.ko *.o *.mod.c *.mod.o *.symvers      10. endif  

# make

# insmod s3c2440_ts.ko

# cat /proc/devices   查看input设备号

# cat /bus/input/devices 查看触摸屏设备信息

# mkdir /dev/input

# mknod /dev/input/event0 c 13 64  添加设备文件

三.测试

编写、编译下面测试程序,运行,点击触摸屏会打印采集的AD转换值。这只是一个简单应用,真正触摸屏应用还需要坐标转换、校正,可参考tslib应用。

   1. #include <stdio.h>  2. #include <stdlib.h>  3. #include <fcntl.h>  4. #include <linux/input.h>  5.   6. struct input_event buff;  7.   8. int main(void)  9. {  10.     int fd;  11.     int ret;  12.     int count=0;  13.       14.     fd = open("/dev/input/event0",O_RDWR);  15.     if(fd<0)  16.     {  17.         perror("can not open event0\n");  18.         return -1;  19.     }  20.   21.     while(1)  22.     {  23.         ret = read(fd,&buff,sizeof(struct input_event));  24.         //if(ret == sizeof(struct input_event))  25.             printf("type:%d\n code:%d\n,value:%d\n",buff.type,buff.code,buff.value);  26.         count++;  27.         printf("count=%d\n",count);  28.     }  29.     close(fd);  30. }  


这篇关于S3C2440驱动篇—触摸屏驱动分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908260

相关文章

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

python-nmap实现python利用nmap进行扫描分析

《python-nmap实现python利用nmap进行扫描分析》Nmap是一个非常用的网络/端口扫描工具,如果想将nmap集成进你的工具里,可以使用python-nmap这个python库,它提供了... 目录前言python-nmap的基本使用PortScanner扫描PortScannerAsync异

Oracle数据库执行计划的查看与分析技巧

《Oracle数据库执行计划的查看与分析技巧》在Oracle数据库中,执行计划能够帮助我们深入了解SQL语句在数据库内部的执行细节,进而优化查询性能、提升系统效率,执行计划是Oracle数据库优化器为... 目录一、什么是执行计划二、查看执行计划的方法(一)使用 EXPLAIN PLAN 命令(二)通过 S

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57