驱动06.触摸屏驱动程序

1.触摸屏的简介

  触摸屏是标准的输入设备,在写驱动程序时采用的之前讲过的输入子系统那套框架。我们无需关心对设备文件的操作,只需关心对硬件寄存器的操作和上报事件即可。

  触摸屏是附在LCD上的一层薄膜,并不是我们平时认识的触摸屏,它只是起到确定坐标的作用。

   S3C2440提供的触摸屏接口有4种处理模式,分别是:正常转换模式、单独的X/Y位置转换模式、自动X/Y位置转换模式和等待中断模式。本例子中用的是等待中断模式

2.以s3c2410_ts.c为例分析整体框架

2.1 s3c2410ts_init函数

1 static int __init s3c2410ts_init(void)
2 {
3 //    init_MUTEX(&gADClock);
4     return platform_driver_register(&s3c2410ts_driver);/*注册s3c2410ts_driver*/
5 }
1 static struct platform_driver s3c2410ts_driver = {
2        .driver         = {
3            .name   = "s3c2410-ts",
4            .owner  = THIS_MODULE,
5        },
6        .probe          = s3c2410ts_probe,
7        .remove         = s3c2410ts_remove,
8 };

如果出现与其同名的平台设备,将调用其probe函数

2.2 s3c2410ts_probe函数

static int __init s3c2410ts_probe(struct platform_device *pdev)
{    /*使能adc时钟*/adc_clock = clk_get(NULL, "adc");clk_enable(adc_clock);//映射adc的地址base_addr=ioremap(S3C2410_PA_ADC,0x20);//配置GPIO,初始化
    s3c2410_ts_connect();//分配一个input_dev结构体input_dev = input_allocate_device();//设置这个结构体ts.dev = input_dev;//事件类型:按键类、绝对位移类ts.dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);ts.dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);//绝对位移类的各种参数:X方向、Y方向、按压类input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);request_irq(IRQ_ADC,stylus_action,...);//ADC中断request_irq(IRQ_TC,stylus_updown,...);//触摸屏中断//注册input_dev结构体
    input_register_device(ts.dev);}

2.3 ADC中断处理函数stylus_action

static irqreturn_t stylus_action(int irq, void *dev_id)
{unsigned long data0;unsigned long data1;//    if (bADCForTS) {
    data0 = ioread32(base_addr+S3C2410_ADCDAT0);data1 = ioread32(base_addr+S3C2410_ADCDAT1);ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;ts.count++;//        bADCForTS = 0;
//        up(&gADClock);if (ts.count < (1<<ts.shift)) {
//                if (!down_trylock(&gADClock)) {
//                    bADCForTS = 1;iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
//            }} else {mod_timer(&touch_timer, jiffies+1);iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);}
//    }return IRQ_HANDLED;
}

2.4 触摸屏中断处理函数stylus_updown

 1 static irqreturn_t stylus_updown(int irq, void *dev_id)
 2 {
 3     unsigned long data0;
 4     unsigned long data1;
 5     int updown;
 6 
 7     data0 = ioread32(base_addr+S3C2410_ADCDAT0);
 8     data1 = ioread32(base_addr+S3C2410_ADCDAT1);
 9 
10     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
11 
12     /* TODO we should never get an interrupt with updown set while
13      * the timer is running, but maybe we ought to verify that the
14      * timer isn't running anyways. */
15 
16     if (updown)
17         touch_timer_fire(0);
18 
19     return IRQ_HANDLED;
20 }
 1 static void touch_timer_fire(unsigned long data) //上报事件
 2 {
 3       unsigned long data0;
 4       unsigned long data1;
 5     int updown;
 6 
 7       data0 = ioread32(base_addr+S3C2410_ADCDAT0);
 8       data1 = ioread32(base_addr+S3C2410_ADCDAT1);
 9 
10      updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
11 
12      if (updown) {
13          if (ts.count != 0) {
14             long tmp;  
15 
16             tmp = ts.xp;
17             ts.xp = ts.yp;
18             ts.yp = tmp;
19 
20              ts.xp >>= ts.shift;
21              ts.yp >>= ts.shift;
22 
23 #ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
24              {
25                  struct timeval tv;
26                  do_gettimeofday(&tv);
27                  printk(DEBUG_LVL "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts.xp, ts.yp);
28              }
29 #endif
30 
31              input_report_abs(ts.dev, ABS_X, ts.xp);
32              input_report_abs(ts.dev, ABS_Y, ts.yp);
33 
34              input_report_key(ts.dev, BTN_TOUCH, 1);
35              input_report_abs(ts.dev, ABS_PRESSURE, 1);
36              input_sync(ts.dev);
37          }
38 
39          ts.xp = 0;
40          ts.yp = 0;
41          ts.count = 0;
42 
43 //        if (!down_trylock(&gADClock)) {
44 //            bADCForTS = 1;
45           iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
46           iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
47 //      }
48      } else {
49          ts.count = 0;
50 
51          input_report_key(ts.dev, BTN_TOUCH, 0);
52          input_report_abs(ts.dev, ABS_PRESSURE, 0);
53          input_sync(ts.dev);
54 
55          iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
56      }
57 }

 

2.5 s3c2410ts_remove,s3c2410ts_exit函数做的工作与上述相反。

3 写代码

3.1 框架

(1)分配一个input_dev结构体

(2)设置

(3)硬件相关的操作(难点)

(4)注册

(5)进一步优化(可有可无,有是最好)       

                                                                                                                   

--------------------------------------------------------------编辑于2017-01-11 00:56:39

   ADC使用的四个步骤:

(1)设置ADCCON寄存器,选择输入信号通道,设置A/D转换器时钟。

(2)设置ADCTSC寄存器,设置其为触摸屏使用。

(3)设置ADCCON寄存器,启动A/D转换。

(4)转换结束时,读取ADCDAT0寄存器获取数值。

  1 /*参考s3c2410_ts.c*/
  2 
  3 #include <linux/errno.h>
  4 #include <linux/kernel.h>
  5 #include <linux/module.h>
  6 #include <linux/slab.h>
  7 #include <linux/input.h>
  8 #include <linux/init.h>
  9 #include <linux/serio.h>
 10 #include <linux/delay.h>
 11 #include <linux/platform_device.h>
 12 #include <linux/clk.h>
 13 #include <asm/io.h>
 14 #include <asm/irq.h>
 15 
 16 #include <asm/plat-s3c24xx/ts.h>
 17 
 18 #include <asm/arch/regs-adc.h>
 19 #include <asm/arch/regs-gpio.h>
 20 
 21 struct s3c_ts_regs{
 22     unsigned long adccon;
 23     unsigned long adctsc;
 24     unsigned long adcdly;
 25     unsigned long adcdat0;
 26     unsigned long adcdat1;
 27     unsigned long adcupdn;
 28 
 29 };
 30 
 31 static struct input_dev *s3c_ts_dev;
 32 static struct clk    *adc_clock;
 33 static volatile struct s3c_ts_regs *s3c_ts_regs;
 34 static struct timer_list ts_timer;
 35 
 36 static void wait_pen_down_mode()
 37 {    
 38     s3c_ts_regs->adctsc = 0xd3;
 39 }
 40 
 41 static void wait_pen_up_mode()
 42 {    
 43     s3c_ts_regs->adctsc = 0x1d3;
 44 }
 45 
 46 static void measure_xy_mode()
 47 {
 48     s3c_ts_regs->adctsc = (1<<3) |(1<<2);
 49 }
 50 
 51 static void start_adc()
 52 {
 53     s3c_ts_regs->adccon |= (1<<0); 
 54 }
 55 
 56 static int s3c_filter_ts(int x[], int y[])
 57 {
 58 #define ERR_LIMIT 10
 59 
 60     int avr_x, avr_y;
 61     int det_x, det_y;
 62 
 63     avr_x = (x[0] + x[1])/2;
 64     avr_y = (y[0] + y[1])/2;
 65 
 66     det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
 67     det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
 68 
 69     if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
 70         return 0;
 71 
 72     avr_x = (x[1] + x[2])/2;
 73     avr_y = (y[1] + y[2])/2;
 74 
 75     det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
 76     det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
 77 
 78     if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
 79         return 0;
 80     
 81     return 1;
 82 }
 83 
 84 static void s3c_ts_timer_func(unsigned long data)
 85 {
 86     if (s3c_ts_regs->adcdat0 & (1<<15))
 87     {
 88         /*pen up*/
 89         input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
 90         input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
 91         input_sync(s3c_ts_dev);
 92         wait_pen_down_mode();
 93     }
 94     else
 95     {
 96         /* 测量X/Y坐标 */
 97         measure_xy_mode();
 98         start_adc();
 99     }
100 }
101 
102 
103 static irqreturn_t tc_irq(int irq, void *dev_id)
104 {    
105     if(s3c_ts_regs->adcdat0 & (1<<15))
106     {
107         /*pen up*/
108         
109          input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
110          input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
111          input_sync(s3c_ts_dev);
112         wait_pen_down_mode();
113 
114     }
115     else
116     {
117         measure_xy_mode();
118         start_adc();
119     }
120     return IRQ_HANDLED;
121 }
122 
123 static irqreturn_t adc_irq(int irq, void *dev_id)
124 {    
125     static int cnt = 0;
126     static int x[4],y[4];
127     int adcdat0, adcdat1;
128 
129     adcdat0 = s3c_ts_regs->adcdat0;
130     adcdat1 = s3c_ts_regs->adcdat1;
131 
132     /*如果发现ADC转换完成后pen up,则丢弃数据*/
133     if(s3c_ts_regs->adcdat0 & (1<<15))
134     {    /*pen up*/
135         cnt = 0;
136         input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
137         input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
138         input_sync(s3c_ts_dev);
139         wait_pen_down_mode();
140     }
141     else
142     {
143         /*多次测量,取平均值*/
144         x[cnt] = adcdat0 & 0x3ff;
145         y[cnt] = adcdat1 & 0x3ff;
146         ++cnt;
147         if (cnt == 4)
148         {
149             /*软件过滤*/
150             if (s3c_filter_ts(x, y))
151             {            
152                 //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
153                 input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
154                 input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
155                 input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
156                 input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
157                 input_sync(s3c_ts_dev);
158             }
159             cnt = 0;
160             wait_pen_up_mode();
161             /*启动定时器实现长按/滑动的情况*/
162             mod_timer(&ts_timer, jiffies + HZ/100);
163 
164         }
165         else
166         {
167             measure_xy_mode();
168             start_adc();
169         }
170 
171             
172     }
173     return IRQ_HANDLED;
174 }
175 
176 
177 
178 static int s3c_ts_init(void)
179 {    /*1.分配一个input_dev结构体*/
180     s3c_ts_dev = input_allocate_device();
181     if (!s3c_ts_dev) {
182         printk(KERN_ERR "Unable to allocate the input device !!\n");
183         return -ENOMEM;
184     }
185 
186     /*2 设置这个结构体*/
187     /*2.1 设置事件类型*/
188     set_bit(EV_KEY,s3c_ts_dev->evbit);
189     set_bit(EV_ABS,s3c_ts_dev->evbit);
190 
191     /*2.2 设置该类型下的哪一个具体事件*/
192     set_bit(BTN_TOUCH,s3c_ts_dev->keybit);
193 
194     input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
195     input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
196     input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
197 
198     /*3 注册*/
199     input_register_device(s3c_ts_dev);
200 
201     /*4 硬件相关的操作*/
202     /*4.1 使能ADC 时钟*/
203     adc_clock = clk_get(NULL, "adc");
204     if (!adc_clock) {
205         printk(KERN_ERR "failed to get adc clock source\n");
206         return -ENOENT;
207     }
208     clk_enable(adc_clock);
209 
210     /*4.2 寄存器初始化*/
211     s3c_ts_regs = ioremap(0x58000000,sizeof(struct s3c_ts_regs));
212     s3c_ts_regs->adccon = (1<<14) |(49<<6);
213 
214     /*4.3 申请中断*/
215     request_irq(IRQ_TC, tc_irq, IRQF_SAMPLE_RANDOM,"tc", NULL);
216     request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM,"adc", NULL);
217 
218     s3c_ts_regs->adcdly = 0xffff;/*待数值稳定后在转换*/
219 
220     init_timer(&ts_timer);
221     ts_timer.function = s3c_ts_timer_func;
222     add_timer(&ts_timer);
223     
224     wait_pen_down_mode();
225     
226     return 0;
227 }
228 
229 static void s3c_ts_exit(void)
230 {
231     free_irq(IRQ_TC, NULL);
232     free_irq(IRQ_ADC, NULL);
233     iounmap(s3c_ts_regs);
234     input_unregister_device(s3c_ts_dev);
235     input_free_device(s3c_ts_dev);
236     del_timer(&ts_timer);
237     
238 }
239 
240 module_init(s3c_ts_init);
241 module_exit(s3c_ts_exit);
242 
243 
244 MODULE_LICENSE("GPL");
触摸屏驱动

--------------------------------------------------------------编辑于2017-01-11 18:21:04

转载于:https://www.cnblogs.com/Lwd-linux/p/6272019.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259742.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2016国产开源软件Top100(Q1)

2016国产开源软件Top100(Q1) 随着互联网的发展、开放标准的普及和虚拟化技术的应用等诸多IT新领域的创新及拓展&#xff0c;开源技术凭借其开放性、低成本、稳定性、灵活性、安全性和技术创新性等特点迅速走向成熟&#xff0c;逐步发展成为一种主流模式&#xff0c;日益改变着全…

mysql lenenc int_MySQL-NonMySQL同步工具源码解读——确定同步位置

经过上一节的鉴权过后&#xff0c;程序已经受主库认可&#xff0c;并且可以像主库发起同步请求。在发起请求之前&#xff0c;还有一个可选的步骤&#xff1a;确认同步时间点。同步时间点由两个属性进行标识&#xff1a;Binlog文件名、偏移量。工具支持自定义时间点&#xff0c;…

DancingLinks刷题集

HDU 3663 Power Stations 精确覆盖 题意&#xff1a;每个城市i有xi->yi天可以成为发射站&#xff0c;发射站覆盖范围为与该站有一条边链接的城市。 同时&#xff0c;每个每天城市必须且只能被一个发射站覆盖 天数D<5。 每个城市的发射站关闭后就不再开启。即只能选择一段…

【web前端优化】前端无优化,庸人自扰之!

前言 我发现一个人厉害不只是他厉害&#xff0c;他的名字也一定要跟着厉害才行&#xff0c;比如我刀狂剑痴叶小钗了&#xff0c;若是老夫叫做刀狂剑痴叶小草&#xff0c;估计就缺少气势了&#xff01;&#xff01;&#xff01; 又如百世经纶一页书&#xff0c;如果叫做百世经纶…

sourceTree添加git密钥步骤

给多个远程服务器比如https://github.com/wangjian2014/wjtest/blob/master/wj.txt添加public密钥 本地服务器添加private密钥 SSH Client 选择PuTTY/Plink 选择Generate&#xff0c;生成public 和private密钥&#xff0c;将public密钥数据复制到远程服务器上面 保存private…

background-size

background-size:contain;contain:包含 按比例调整图片&#xff0c;使得图片的宽度自适应容器的宽度。 相当于在ps中&#xff0c;约束比例设置原始图片的宽度值等于容器的宽度值。 如果图片过大&#xff0c;等比压缩后容器的高度方向上可能会有空白。 background-size:cover;co…

MySQL5.6免安装配置与“系统找不到指定的文件”错误

1.下载免安装版本的mysql-5.6.11-winx64 (本机 win7 64位)2.将文件解压到任意&#xff0c;不要有中文&#xff08;有中文的情况没试过&#xff0c;不过最好避免这种情况&#xff09;3.配置mysql 环境变量&#xff0c;在 path后面加上D:\Program Files\mysql-5.6.11-winx64\bin…

Source Insight基本使用和快捷键

为什么要用Source Insight呢&#xff1f;貌似是因为比完整的IDE要更快一些&#xff0c;比较利于查看大量的代码。 软件的安装很简单&#xff0c;设置好安装目录。 配置好文档路径&#xff0c;当然这个也可以在Options里面改&#xff0c;选Options->Preferences…里面的Folde…

powerquery mysql数据库_window 10 下 --excel | power query 通过 ODBC链接 mysql 数据库

excel链接到mysql的方法有几种&#xff0c;今天主要介绍如何通过ODBC链接odbc是 “开放数据库连接”&#xff0c;你可以通过下载插件使得自己的excel可以连接到不同的数据库。关于版本的选择&#xff0c;就是excel版本obdc版本mysql obdc版本(需要一样)第一步 下载mysql odbc…

table样式

一直以来&#xff0c;css和JS都是软肋&#xff0c;因为需要不得不重新温故。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><style type"text/css">table.hover…

MAC和XCODE常用快捷键

摘自&#xff1a;http://www.cnblogs.com/yjmyzz/archive/2011/01/25/1944325.html 1. 文件CMD N: 新文件CMD SHIFT N: 新项目CMD O: 打开CMD S: 保存CMD SHIFT S: 另存为CMD W: 关闭窗口CMD SHIFT W: 关闭文件2. 编辑CMD [: 左缩进CMD ]: 右缩进CMD CTRL LEFT: …

数组与内存控制

注&#xff1a;我已对本文章进行了更新&#xff0c;劳烦移步。 java语言是典型的静态语言&#xff0c;因而&#xff0c;数组也是静态的&#xff0c;即当该数组被初始化之后&#xff0c;该数组的长度是不可变的。java 语言的数组变量是引用类型&#xff0c;什么意思呢&#xff1…

NRedis-Proxy - 高性能中间件服务器

2019独角兽企业重金招聘Python工程师标准>>> 高性能中间件服务器 一、 NRedis-Proxy 介绍 NRedis-Proxy 是一个Redis中间件服务&#xff0c;第一个Java 版本开源Redis中间件&#xff0c;无须修改业务应用程序任何代码与配置&#xff0c;与业务解耦&#xff1b;以Spr…

CVE-2014-4877 wget: FTP Symlink Arbitrary Filesystem Access

目录 1. 漏洞基本描述 2. 漏洞带来的影响 3. 漏洞攻击场景重现 4. 漏洞的利用场景 5. 漏洞原理分析 6. 漏洞修复方案 7. 攻防思考 1. 漏洞基本描述 0x1: Wget简介 wget是一个从网络上自动下载文件的自由工具&#xff0c;支持通过HTTP、HTTPS、FTP三个最常见的TCP/IP协议下载&am…

mysql-nt.exe w3wp.exe cpu 100%_w3wp.exe(IIS ) CPU 占用 100% 的常见原因及解决办法

对于IIS管理员来说&#xff0c;经常会碰到Web服务器CPU占用100%的情况&#xff0c;以下是个人的日常工作总结和一些解决办法&#xff0c;主要用来剖析w3wp.exe(IIS )占用CPU 100%的一些原因 和解决方案&#xff0c;希望能对你有所帮助w3wp.exe的解释:全名&#xff0c;IIS Appli…

TOP结果详解

2019独角兽企业重金招聘Python工程师标准>>> TOP前5行 top - 16:24:25 up 284 days, 4:59, 1 user, load average: 0.10, 0.05, 0.01 top 当前时间、系统启动时间、当前系统登录用户数目、平均负载&#xff08;1分钟,10分钟,15分钟&#xff09;。平均负载&#x…

BZOJ3236 [Ahoi2013]作业

昨天晚上做的。。。差错一直查到今天 最后没办法问管理员要了数据才知道原来ans数组开小了233&#xff0c;简直沙茶 这道题不就是裸的莫队嘛 ||| 只要用树状数组维护当前的两种个数即可。 1 /**************************************************************2 Problem: 3…

mysql ddl dml 导出_MySQL:DDL和DML语句,弄明白了吗?

语句分类DDL&#xff08;Data Definition Languages&#xff09;语句&#xff1a;即数据库定义语句&#xff0c;用来创建数据库中的表、索引、视图、存储过程、触发器等&#xff0c;常用的语句关键字有&#xff1a;CREATE,ALTER,DROP,TRUNCATE,COMMENT,RENAME。增删改表的结构D…

敏捷水手——单体法到微服务之旅

\本文要点\\探究持续四年多的渐进式改革是什么样子&#xff1b;\\t探索为什么在变革软件和组织设计时要遵循康威定律&#xff1b;\\t看看如何将领导力应用到不同的团队、领域和层级&#xff1b;\\t举例说明变革管理如何依赖于理念和一贯的长远目标&#xff1b;\\t了解从职能型团…

SQLCMD的介绍

SQLCMD的介绍 原文:SQLCMD的介绍文章转载自&#xff1a;http://blog.sina.com.cn/s/blog_3eec0ced0100mhm2.html最近经常用到超过80M *.sql文件的导入问题。上网找了一下&#xff0c;发现超过80M的文件是不能在查询分析器中执行的。找了些解决方案&#xff0c;个人感觉最简单的…