一. device的注册
1.0 两个注册
//在smdk6410_machine_init中既注册了touchscreen的私有信息也注册了ts资源

  1. 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.  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.  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.  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函数

  1. 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.  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.  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.  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

  1. static struct timer_list touch_timer =
  2. TIMER_INITIALIZER(touch_timer_fire, 0, 0);

IRQ_ADC中断处理函数:

  1.  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触摸屏驱动分析的更多相关文章

  1. ARM-Linux驱动-触摸屏驱动分析

    出处:http://blog.csdn.net/geekcome/article/details/6580981 硬件平台:FL2440 内核版本:2.6.28 主机平台:Ubuntu 11.04 内 ...

  2. mini2440触摸屏驱动分析

    mini2440驱动分析系列之 ---------------------------------------Mini2440触摸屏程序分析 By JeefJiang July,8th,2009 这是 ...

  3. S3C6410 LCD驱动分析(转)

    一. 理论分析1. 几个概念:FIMC :    Fully Interactive Mobile Camera (完全交互式移动摄像机)FIMD:     Fully Interactive Mob ...

  4. i2c触摸屏驱动文件的实现

    转自:http://blog.chinaunix.net/uid-29507718-id-4314013.html Linux下I2C接口触摸屏驱动分析  分类: LINUX linux下触摸屏驱动的 ...

  5. Linux触摸驱动分析

    测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 触摸屏基础知识 一.结构 上图是电阻触摸屏的一个侧面剖视图 ...

  6. 【驱动】input子系统整体流程全面分析(触摸屏驱动为例)【转】

    转自:http://www.cnblogs.com/lcw/p/3294356.html input输入子系统整体流程 input子系统在内核中的实现,包括输入子系统(Input Core),事件处理 ...

  7. 【Linux高级驱动】触摸屏驱动的移植

    触摸屏驱动的移植 流程 注意:看框架图 1.添加input.c组件 Device Drivers  ---> Input device support  --->  Generic inp ...

  8. S3C2440触摸屏驱动实例开发讲解

    出处:http://www.embeddedlinux.org.cn/html/yingjianqudong/ 一.开发环境 主  机:VMWare--Fedora 9 开发板:Mini2440--6 ...

  9. AM335x(TQ335x)学习笔记——触摸屏驱动编写

    前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱 ...

随机推荐

  1. Activiti7 使用监听器分配任务人员

    视屏中老师说,一般没有人用但是我还是想试试 但是当我画图的时候,发现IDEA的那个listener监听器点不开,不知道是不是我下载的插件不对还是什么原因,所以就亲自写了,看看到时候不行就下载一个Ecl ...

  2. 详解JVM中的内存模型是什么?

    强烈推荐 不管是找工作还是提升水平,都建议读一下<深入理解Java虚拟机>这本书,详细讲解了JVM中的内存管理.类加载过程.垃圾回收以及最重要的性能调优实战. 本博客也是参考了这本书,有不 ...

  3. 别再眼高手低了! 这些Linq方法都清楚地掌握了吗?

    不要再眼高手低了,这些Enumerable之常见Linq扩展方法都清楚掌握了吗?其实这是对我自己来说的! 例如:一个人这个技术掌握了一点那个技术也懂一点,其他的好像也了解一些,感觉自己啥都会一点,又觉 ...

  4. 如何借助 IDEA 数据库管理工具可视化使用 TDengine?

    什么是IDEA Database管理工具? 这里首先介绍下IDEA,IDEA全称IntelliJ IDEA,是Java语言开发的集成环境,IntelliJ在业界被公认为最好的Java开发工具之一. I ...

  5. javac中不引人注目的编码小坑

    来看下面这段java程序: public class Test{ public static void main(String[] args){ System.out.println("哈哈 ...

  6. 集群实战(2):K8S集群节点退出加入操作

    以下报错网上其实也可以找到并解决,但是偏零碎我只是根据自己的在使用中遇到的问题做个汇总. 文章目录 首先删掉节点 node重新加入 参考文档 首先删掉节点 注意:以下操作都是在master下操作. 一 ...

  7. yum管理——yum常用配置(2)

    一.网络源的缓存设置 [root@yunwei ~]# vim /etc/yum.conf [main] cachedir=/var/cache/yum/$basearch/$releasever k ...

  8. react项目结合echarts,百度地图实现热力图

    一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...

  9. netty字符串流分包

    @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Obj ...

  10. java 判断jsonObject 对象为null的天坑问题

    jsonObject = {"mmbRetrieveBookingResponse":{"bookingData":null,"isAfterTran ...