S3C6410触摸屏驱动分析
1.0 两个注册
//在smdk6410_machine_init中既注册了touchscreen的私有信息也注册了ts资源
1 在arch/arm/mach-s3c64xx/mach-smdk6410.c中
2 static void __init smdk6410_machine_init(void)
3 {
4 //在arch/arm/mach-s3c64xx/dev-ts.c中
5 s3c_ts_set_platdata(&s3c_ts_platform); //1.设备私有信息的注册
6 //在driver/base/platform.c中
7 platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices)); //2.设备资源的注册
8 }
1.1 ts私有信息的注册
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
1 static struct s3c_ts_mach_info s3c_ts_platform __initdata = {
2 .delay = 10000, //延时
3 .presc = 49, //分频
4 .oversampling_shift = 2, //分频
5 .resol_bit = 12, //精度
6 .s3c_adc_con = ADC_TYPE_2, //分频
7 };
8 smdk6410_machine_init
9 {
10 //下面这个函数在arch/arm/mach-s3c64xx/dev-ts.c中
11 s3c_ts_set_platdata(&s3c_ts_platform);
12 }
1.2 ts设备资源的注册
1 //在arch/arm/mach-s3c64xx/dev-ts.c中
2 static struct resource s3c_ts_resource[] = {
3 [0] = {
4 .start = SAMSUNG_PA_ADC, //0x7E00B000
5 .end = SAMSUNG_PA_ADC + SZ_256 - 1, //0x7E00B100
6 .flags = IORESOURCE_MEM,
7 },
8 [1] = {
9 .start = IRQ_PENDN, //0x5e=94
10 .end = IRQ_PENDN,
11 .flags = IORESOURCE_IRQ,
12 },
13 [2] = {
14 .start = IRQ_ADC, //0x5f=95
15 .end = IRQ_ADC,
16 .flags = IORESOURCE_IRQ,
17 }
18 };
19 struct platform_device s3c_device_ts = {
20 .name = "s3c-ts",
21 .id = -1,
22 .num_resources = ARRAY_SIZE(s3c_ts_resource),
23 .resource = s3c_ts_resource,
24 };
25 //在arch/arm/mach-s3c64xx/mach-smdk6410.c中
26 static struct platform_device *smdk6410_devices[] __initdata = {
27 &s3c_device_ts, //把ts放入到总的ts列表中
28 }
29 //在arch/arm/mach-s3c64xx/mach-smdk6410.c中
30 static void __init smdk6410_machine_init(void)
31 {
32 //在driver/base/platform.c中一起注册
33 platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
34 }
二. device_driver
2.0 两个宏
1 #define WAIT4INT(x) //只是针对于S3C_ADCTSC寄存器
2 (((x)<<8) | //<bit8> 0->down 1->up interrupt signal
3 S3C_ADCTSC_YM_SEN | //<bit7> 1 = Switch enable (YM = VSSA_ADC)
4 S3C_ADCTSC_YP_SEN | //<bit6> 1 = Switch disable (YP=AIN5, Hi-z)
5 //XM_SEN //<bit5> 0 = Switch disable (XM = AIN6, Hi-z)
6 S3C_ADCTSC_XP_SEN | //<bit4> 1 = Switch disable (XP=AIN7, Hi-z)
7 //PULL_UP //<bit3> 0 = XP Pull-up Enable.
8 //AUTO_PST //<bit2> 0 = Normal ADC conversion.
9 S3C_ADCTSC_XY_PST(3)) //<bit1-0> 3: Waiting for Interrupt Mode
10 #define AUTOPST
11 (S3C_ADCTSC_YM_SEN | //1 = Switch enable (YM = VSSA_ADC)
12 S3C_ADCTSC_YP_SEN | //1 = Switch disable (YP=AIN5, Hi-z)
13 S3C_ADCTSC_XP_SEN | //1 = Switch disable (XP=AIN7, Hi-z)
14 S3C_ADCTSC_AUTO_PST | //1 = Auto Sequential measurement of X-position, Y-position
15 S3C_ADCTSC_XY_PST(0)) //0 = No operation mode
16 WAIT4INT(x) :
17 当x=0时,设为等侍down中断
18 当x=1时,设为等侍up中断
2.1 初始化
ok6410的touchscreen在内核源码的位置:driver/input/touchscreen/s3c-ts.c
device 与 device_driver按名字s3c-ts匹配之后,就进入s3c_ts_probe函数
static struct platform_driver s3c_ts_driver = {
.probe = s3c_ts_probe,
.remove = s3c_ts_remove,
.suspend = s3c_ts_suspend,
.resume = s3c_ts_resume,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-ts",
},
};
static int __init s3c_ts_init(void)
{
return platform_driver_register(&s3c_ts_driver);
}
static void __exit s3c_ts_exit(void)
{
platform_driver_unregister(&s3c_ts_driver);
}
module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
2.2 probe函数
1 static int __init s3c_ts_probe(struct platform_device *pdev)
2 {
3 struct resource *res;
4 struct device *dev;
5 struct input_dev *input_dev;
6 struct s3c_ts_mach_info * s3c_ts_cfg;
7 int ret, size;
8 dev = &pdev->dev;
9 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取ts寄存器地址
10 size = (res->end - res->start) + 1;
11 ts_mem = request_mem_region(res->start, size, pdev->name); //申请I/O内存
12 ts_base = ioremap(res->start, size); //request_mem_region申请的内存在使用前要调用ioremap
13 ts_clock = clk_get(&pdev->dev, "adc"); //获取clock
14 clk_enable(ts_clock); //在初始化时disable了ts_clock,这个地方要enable
15
16 //下面这几行是要把ts的配置信息写到寄存器中去
17 s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev); //获取ts的配置信息,
18 //ts的私有信息:在arch/arm/mach-s3c64xx/mach-smdk6410.c中
19 //enable prescaler && 设置prescaler_value=s3c_ts_cfg->presc
20 writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xff), ts_base+S3C_ADCCON);
21
22 //s3c_ts_cfg->delay=0x10000 --> External input clock
23 writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);
24
25 //A/D converter resolution selection--> 12-bit A/D conversion
26 writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);
27 //设为等侍down中断模式
28 writel(WAIT4INT(0), ts_base+S3C_ADCTSC);
29 ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL); //下面这几行是要初始化s3c_ts_info结构体
30 input_dev = input_allocate_device();
31
32 ts->dev = input_dev;
33 ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
34 ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
35 if (s3c_ts_cfg->resol_bit==12) {
36 input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0); //设置x轴的最大最小值
37 input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0); //设置y轴的最大最小值
38 }
39 input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0); //设置Press状态的最大最小值(按下或空闲)
40 sprintf(ts->phys, "input(ts)");
41 ts->dev->name = s3c_ts_name;
42 ts->dev->phys = ts->phys;
43 ts->dev->id.bustype = BUS_RS232;
44 ts->dev->id.vendor = 0xDEAD;
45 ts->dev->id.product = 0xBEEF;
46 ts->dev->id.version = S3C_TSVERSION;
47 ts->shift = s3c_ts_cfg->oversampling_shift;
48 ts->resol_bit = s3c_ts_cfg->resol_bit;
49 ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;
50 /* For IRQ_PENDUP */
51 ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //获取中断号
52 //申请中断,RANDOM表示设备可以看作随机的发生源
53 ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts); //申请中断
54
55 /* For IRQ_ADC */
56 ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1); //获取中断号
57 ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM | IRQF_SHARED, "s3c_action", ts); //申请共享中断
58
59 /* All went ok, so register to the input system */
60 ret = input_register_device(ts->dev); //把这个input_dev添加到input系统中
61 }
ts底板图:
ts连到核心板图:
TSXP --> AIN7
TSYP --> AIN5
2.3 IRQ_PENDN
1 static irqreturn_t stylus_updown(int irqno, void *param)
2 {
3 unsigned long data0;
4 unsigned long data1;
5 if (!ADC_locked4TS()) //进入中断函数,如果没有加锁,则加上锁
6 if (s3c_ts_adc_lock(LOCK_TS)) //如果加锁失败,则直接返回
7 return IRQ_HANDLED;
8 data0 = readl(ts_base+S3C_ADCDAT0);
9 data1 = readl(ts_base+S3C_ADCDAT1);
10 touch_timer_fire(0);
11 if(ts->s3c_adc_con==ADC_TYPE_2) {
12 //ADCCLRINTPNDNUP: INT_PNDNUP interrupt clear
13 __raw_writel(0x0, ts_base+S3C_ADCCLRWK);
14 //ADCCLRINT: Clear ADC Interrupt
15 __raw_writel(0x0, ts_base+S3C_ADCCLRINT);
16 }
17 return IRQ_HANDLED;
18 }
2.3.1 fire
1 static void touch_timer_fire(unsigned long data)
2 {
3 unsigned long data0;
4 unsigned long data1;
5 int pendown;
6 if (!ADC_locked4TS()) //如果当前状态是free,说明加锁失败,直接返回
7 return;
8
9 //这儿的数据读取,是为了判断是down还是up状态
10 data0 = readl(ts_base+S3C_ADCDAT0); //读
11 data1 = readl(ts_base+S3C_ADCDAT1); //读
12 //data0的bit15: 0->按下状态; 1->松开状态
13 //如果data0与data1都不为松开状态,就是按下状态
14 pendown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));
15 if (pendown) { //在按下状态,如果有数据则提交数据,
16 if (ts->count) { //这个ts->count是在IRQ_ADC中改变的
17 input_report_abs(ts->dev, ABS_X, ts->xp); //提交
18 input_report_abs(ts->dev, ABS_Y, ts->yp); //提交
19 input_report_key(ts->dev, BTN_TOUCH, 1); //提交
20 input_report_abs(ts->dev, ABS_PRESSURE, 1); //提交
21 input_sync(ts->dev); //提交
22 } //ts->count>0,说明ADC己经转化过数据了,就提交完数据,
23 ts->xp = 0; //然后把所有数据归零
24 ts->yp = 0;
25 ts->count = 0;
26 //设ADC的模式为自动转换
27 writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);
28 //ADCCON bit0 --> A/D conversion starts: 启动adc转换,产生一个IRQ_ADC中断
29 //注意:这儿是要启动ADC中断,但具体是down还是up中断
30 writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);
31 }
32 else { //如果是松开
33 ts->count = 0;
34 input_report_key(ts->dev, BTN_TOUCH, 0); //提交
35 input_report_abs(ts->dev, ABS_PRESSURE, 0); //提交
36 input_sync(ts->dev);
37 writel(WAIT4INT(0), ts_base+S3C_ADCTSC); //等侍按下中断
38 if (ADC_locked4TS()) //如果还处于锁定状态
39 s3c_ts_adc_unlock(); //释放锁,表示一次按键结束
40 }
41 }
注意:
在按下状态,先提交数据,产生ADC中断,
在松开状态,先提交数据,切换为按下中断
2.4 IRQ_ADC
在进入IRQ_ADC中断之前,己经定义了一个时间定时器,它的处理函数是 touch_timer_fire
- static struct timer_list touch_timer =
- TIMER_INITIALIZER(touch_timer_fire, 0, 0);
IRQ_ADC中断处理函数:
1 static irqreturn_t stylus_action(int irqno, void *param)
2 {
3 unsigned long data0;
4 unsigned long data1;
5 if (!ADC_locked4TS()) { //如果处于未锁定状态,说明出错
6 if (ADC_free()) //锁是在IRQ_TS中加上的
7 __raw_writel(0x0, ts_base + S3C_ADCCLRINT);
8 return IRQ_HANDLED;
9 }
10 data0 = readl(ts_base+S3C_ADCDAT0); //读
11 data1 = readl(ts_base+S3C_ADCDAT1); //读
12 if(ts->resol_bit==12) {
13 ts->xp += data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT; //怎么能让我相信这是在求平均值呢?
14 ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT;
15 }
16 ts->count++;
17 if (ts->count < (1<<ts->shift)) { //小于4次,ts->shift=2
18 writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);
19 writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);
20 } else { //超过4次,则
21 //启动定时器,把超时时间设为jiffies+1,调用touch_timer_fire
22 mod_timer(&touch_timer, jiffies+1);
23 //等侍松开
24 writel(WAIT4INT(1), ts_base+S3C_ADCTSC);
25 }
26 if(ts->s3c_adc_con==ADC_TYPE_2) {
27 //ADCCLRINTPNDNUP: INT_PNDNUP interrupt clear
28 __raw_writel(0x0, ts_base+S3C_ADCCLRWK);
29 //ADCCLRINT: Clear ADC Interrupt
30 __raw_writel(0x0, ts_base+S3C_ADCCLRINT);
31 }
32 return IRQ_HANDLED;
33 }
注意:
在按下状态,先提交数据,产生ADC中断,
在松开状态,先提交数据,切换为按下中断
三.总结
3.1 按下到松开时的流程如下:
3.2 文字说明
初始化时设为等侍down中断模式
当有触摸笔按下时:
a.触发中断,进入stylus_updown函数
stylus_updown:判断是down中断, 如果ts->count,触发adc中断
b.触发ADC中断,进入stylus_action函数
stylus_action: ts->count小于4次, 触发adc中断;
继续自动检测,直到満足4次
stylus_action: 时间定时器触发touch_timer_fire,并切换到等侍up中断模式
c. touch_timer_fire:
判断是down中断,汇报坐标信息,触发adc中断,与b进入循环
持继汇报触摸笔按下信息
当有触摸笔松开时:
a. touch_timer_fire:
判断是up中断,汇报坐标信息,切换到等侍按下中断
S3C6410触摸屏驱动分析的更多相关文章
- ARM-Linux驱动-触摸屏驱动分析
出处:http://blog.csdn.net/geekcome/article/details/6580981 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11.04 内 ...
- mini2440触摸屏驱动分析
mini2440驱动分析系列之 ---------------------------------------Mini2440触摸屏程序分析 By JeefJiang July,8th,2009 这是 ...
- S3C6410 LCD驱动分析(转)
一. 理论分析1. 几个概念:FIMC : Fully Interactive Mobile Camera (完全交互式移动摄像机)FIMD: Fully Interactive Mob ...
- i2c触摸屏驱动文件的实现
转自:http://blog.chinaunix.net/uid-29507718-id-4314013.html Linux下I2C接口触摸屏驱动分析 分类: LINUX linux下触摸屏驱动的 ...
- Linux触摸驱动分析
测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 触摸屏基础知识 一.结构 上图是电阻触摸屏的一个侧面剖视图 ...
- 【驱动】input子系统整体流程全面分析(触摸屏驱动为例)【转】
转自:http://www.cnblogs.com/lcw/p/3294356.html input输入子系统整体流程 input子系统在内核中的实现,包括输入子系统(Input Core),事件处理 ...
- 【Linux高级驱动】触摸屏驱动的移植
触摸屏驱动的移植 流程 注意:看框架图 1.添加input.c组件 Device Drivers ---> Input device support ---> Generic inp ...
- S3C2440触摸屏驱动实例开发讲解
出处:http://www.embeddedlinux.org.cn/html/yingjianqudong/ 一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--6 ...
- AM335x(TQ335x)学习笔记——触摸屏驱动编写
前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱 ...
随机推荐
- Activiti7 使用监听器分配任务人员
视屏中老师说,一般没有人用但是我还是想试试 但是当我画图的时候,发现IDEA的那个listener监听器点不开,不知道是不是我下载的插件不对还是什么原因,所以就亲自写了,看看到时候不行就下载一个Ecl ...
- 详解JVM中的内存模型是什么?
强烈推荐 不管是找工作还是提升水平,都建议读一下<深入理解Java虚拟机>这本书,详细讲解了JVM中的内存管理.类加载过程.垃圾回收以及最重要的性能调优实战. 本博客也是参考了这本书,有不 ...
- 别再眼高手低了! 这些Linq方法都清楚地掌握了吗?
不要再眼高手低了,这些Enumerable之常见Linq扩展方法都清楚掌握了吗?其实这是对我自己来说的! 例如:一个人这个技术掌握了一点那个技术也懂一点,其他的好像也了解一些,感觉自己啥都会一点,又觉 ...
- 如何借助 IDEA 数据库管理工具可视化使用 TDengine?
什么是IDEA Database管理工具? 这里首先介绍下IDEA,IDEA全称IntelliJ IDEA,是Java语言开发的集成环境,IntelliJ在业界被公认为最好的Java开发工具之一. I ...
- javac中不引人注目的编码小坑
来看下面这段java程序: public class Test{ public static void main(String[] args){ System.out.println("哈哈 ...
- 集群实战(2):K8S集群节点退出加入操作
以下报错网上其实也可以找到并解决,但是偏零碎我只是根据自己的在使用中遇到的问题做个汇总. 文章目录 首先删掉节点 node重新加入 参考文档 首先删掉节点 注意:以下操作都是在master下操作. 一 ...
- yum管理——yum常用配置(2)
一.网络源的缓存设置 [root@yunwei ~]# vim /etc/yum.conf [main] cachedir=/var/cache/yum/$basearch/$releasever k ...
- react项目结合echarts,百度地图实现热力图
一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...
- netty字符串流分包
@Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Obj ...
- java 判断jsonObject 对象为null的天坑问题
jsonObject = {"mmbRetrieveBookingResponse":{"bookingData":null,"isAfterTran ...