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官方内核中也没有带该触摸屏的驱 ...
随机推荐
- 1dialog 表单最基本的封装
<!-- --> <template> <el-dialog :visible.sync="defaultConfigDialogAdd.dialogVisib ...
- OpenvSwitch系列之七 meter表限速
Open vSwitch系列之一 Open vSwitch诞生 Open vSwitch系列之二 安装指定版本ovs Open vSwitch系列之三 ovs-vsctl命令使用 Open vSwit ...
- WebApi 接口传参接参
阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4.“怪异”的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4.后台发送请求参数的 ...
- 同样是logback1.11,更换了log配置后,无论是否有线程持续不断写入log文件,log文件会按设定以日期序号轮换
上次发现了logback1.11的一个bug,即有线程持续写入log,则log文件不会按设定模式进行轮换. 但发现同样采用logback1.11的另外一个工程,它的日志文件就没有错误,于是参照其配置文 ...
- i春秋公益赛之signin
题目链接:https://buuoj.cn/challenges#gyctf_2020_signin 查看程序保护 只开了canary和NX保护,在IDA查看反编译出来的为代码时发现程序给了一个后门 ...
- C#开发PACS医学影像处理系统(二):界面布局之菜单栏
在菜单栏布局上,为了使用自定义窗体样式和按钮,我们需要先将窗体设置为无边框,然后添加一个Grid作为菜单栏并置顶,VerticalAlignment="Top" logo图片和标题 ...
- Java中AQS基本实现原理
一.AQS概述 AQS全名AbstractQueuedSynchronizer,意为抽象队列同步器,JUC(java.util.concurrent包)下面的Lock和其他一些并发工具类都是基于它来实 ...
- JS -- 操作符和数组
一.Javascript常用操作符 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...
- get、post请求方式在jmeter中使用步骤
jmeter:性能测试工具,压测 一.jmeter工具测试接口时使用步骤: 1.测试计划右键--添加--Threads(Users)--线程组(线程数就是并发数) 2.线程组右键--Sampler-- ...
- 故事:坐在我隔壁的小王问我什么是HyperLogLog
1 最近坐我隔壁的小王同志,心情真是糟透了.不但工作不顺心,被老板狠狠的批了一顿,连女朋友也跟别人跑了(Y 的让你天天在我面前秀). 真是不可谓不惨,我都快要同情他了. 看着他萎靡又迷离的眼神,我实在 ...