查看input系统

  1. root@OK6410:~# cat /proc/bus/input/devices
  2. I: Bus=0013 Vendor=dead Product=beef Version=0101
  3. N: Name="S3C TouchScreen"
  4. P: Phys=input(ts)
  5. S: Sysfs=/devices/virtual/input/input2
  6. U: Uniq=
  7. H: Handlers=mouse0 event2
  8. B: PROP=0
  9. B: EV=b
  10. B: KEY=400 0 0 0 0 0 0 0 0 0 0
  11. B: ABS=1000003

一. device的注册
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中
    static void __init smdk6410_machine_init(void)
    {
        //在driver/base/platform.c中一起注册
        platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
    }

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

WAIT4INT(x) :
            当x=0时,设为等侍down中断
             当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 = {
  2. .probe = s3c_ts_probe,
  3. .remove = s3c_ts_remove,
  4. .suspend = s3c_ts_suspend,
  5. .resume = s3c_ts_resume,
  6. .driver        = {
  7. .owner    = THIS_MODULE,
  8. .name    = "s3c-ts",
  9. },
  10. };
  11. static int __init s3c_ts_init(void)
  12. {
  13. return platform_driver_register(&s3c_ts_driver);
  14. }
  15. static void __exit s3c_ts_exit(void)
  16. {
  17. platform_driver_unregister(&s3c_ts_driver);
  18. }
  19. module_init(s3c_ts_init);
  20. 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. //下面这几行是要把ts的配置信息写到寄存器中去
  16. s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev);                        //获取ts的配置信息,
  17. //ts的私有信息:在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  18. //enable prescaler && 设置prescaler_value=s3c_ts_cfg->presc
  19. writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xff), ts_base+S3C_ADCCON);
  20. //s3c_ts_cfg->delay=0x10000 --> External input clock
  21. writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);
  22. //A/D converter resolution selection--> 12-bit A/D conversion
  23. writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);
  24. //设为等侍down中断模式
  25. writel(WAIT4INT(0), ts_base+S3C_ADCTSC);
  1. ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);           //下面这几行是要初始化s3c_ts_info结构体
  2. input_dev = input_allocate_device();
  3. ts->dev = input_dev;
  4. ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
  5. ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  6. if (s3c_ts_cfg->resol_bit==12) {
  7. input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);                //设置x轴的最大最小值
  8. input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);                //设置y轴的最大最小值
  9. }
  10. input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);                 //设置Press状态的最大最小值(按下或空闲)
  11. sprintf(ts->phys, "input(ts)");
  12. ts->dev->name = s3c_ts_name;
  13. ts->dev->phys = ts->phys;
  14. ts->dev->id.bustype = BUS_RS232;
  15. ts->dev->id.vendor = 0xDEAD;
  16. ts->dev->id.product = 0xBEEF;
  17. ts->dev->id.version = S3C_TSVERSION;
  18. ts->shift = s3c_ts_cfg->oversampling_shift;
  19. ts->resol_bit = s3c_ts_cfg->resol_bit;
  20. ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;
  21. /* For IRQ_PENDUP */
  22. ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);                //获取中断号
  23. //申请中断,RANDOM表示设备可以看作随机的发生源
  24. ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts); //申请中断
  25. /* For IRQ_ADC */
  26. ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);               //获取中断号
  27. ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM | IRQF_SHARED, "s3c_action", ts); //申请共享中断
  28. /* All went ok, so register to the input system */
  29. ret = input_register_device(ts->dev);                                    //把这个input_dev添加到input系统中
  30. }

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. //这儿的数据读取,是为了判断是down还是up状态
  9. data0 = readl(ts_base+S3C_ADCDAT0);         //读
  10. data1 = readl(ts_base+S3C_ADCDAT1);         //读
  11. //data0的bit15: 0->按下状态; 1->松开状态
  12. //如果data0与data1都不为松开状态,就是按下状态
  13. pendown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));
  14. if (pendown) {           //在按下状态,如果有数据则提交数据,
  15. if (ts->count) {     //这个ts->count是在IRQ_ADC中改变的
  16. input_report_abs(ts->dev, ABS_X, ts->xp);     //提交
  17. input_report_abs(ts->dev, ABS_Y, ts->yp);     //提交
  18. input_report_key(ts->dev, BTN_TOUCH, 1);       //提交
  19. input_report_abs(ts->dev, ABS_PRESSURE, 1);    //提交
  20. input_sync(ts->dev);                           //提交
  21. }                      //ts->count>0,说明ADC己经转化过数据了,就提交完数据,
  22. ts->xp = 0;            //然后把所有数据归零
  23. ts->yp = 0;
  24. ts->count = 0;
  25. //设ADC的模式为自动转换
  26. writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);
  27. //ADCCON bit0 --> A/D conversion starts: 启动adc转换,产生一个IRQ_ADC中断
  28. //注意:这儿是要启动ADC中断,但具体是down还是up中断
  29. writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);
  30. }
  31. else {                    //如果是松开
  32. ts->count = 0;
  33. input_report_key(ts->dev, BTN_TOUCH, 0);        //提交
  34. input_report_abs(ts->dev, ABS_PRESSURE, 0);     //提交
  35. input_sync(ts->dev);
  36. writel(WAIT4INT(0), ts_base+S3C_ADCTSC);    //等侍按下中断
  37. if (ADC_locked4TS())                       //如果还处于锁定状态
  38. s3c_ts_adc_unlock();                   //释放锁,表示一次按键结束
  39. }
  40. }

注意: 
在按下状态,先提交数据,产生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. 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中断,汇报坐标信息,切换到等侍按下中断

Linux内核---30.触摸屏驱动分析相关推荐

  1. linux内核SPI总线驱动分析(一)

    下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) SPI总线驱动分析   1 SPI概述     ...

  2. linux内核关闭触摸屏校准,linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand...

    近期给客户调试一块数控板,今天客户带过来一个屏,并且有一个usb的触摸屏芯片接在屏上.屏很快就弄好正常显示. 触摸屏在内核下找到usb 触摸屏驱动,内核启动后这个usb转的触摸屏也正常找到,注册为ev ...

  3. linux内核spi总线驱动分析,Linux下的SPI总线驱动(三)

    版权所有,转载请说明转自 原创作者:南京邮电大学  通信与信息系统专业 研二 魏清 五.SPI测试代码 对于SPI总线驱动,我们可以分为SPI控制设备驱动和SPI接口设备驱动.而作为驱动开发人员主要是 ...

  4. Linux内核---31.按键驱动分析(未完成)

    一. device的注册 1.0 按键设备的注册 按键设备的定义在arch/arm/mach-s3c64xx中 /* gpio buttons */ static struct gpio_keys_b ...

  5. Linux内核的Nand驱动流程分析

    最近在做Linux内核移植,总体的感觉是这样的,想要彻底的阅读Linux内核代码几乎是不可能的,至少这还不是嵌入式学期初期的重要任务.内核代码解压后有250M左右,据统计,有400多万行,而且涉及到了 ...

  6. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析

    Linux内核抢占实现机制分析 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/ ...

  7. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的&qu ...

  8. linux rs232触摸屏驱动程序,Linux下的触摸屏驱动

    一.触摸屏理论概述 对于触摸屏驱动,我们主要需要掌握触摸屏驱动代码和应用层测试代码.下面讲的是基于Mini2440的触摸屏驱动,现在的驱动我们都将设备和驱动分离,挂在平台设备总线上,让设备和驱动去匹配 ...

  9. linux内核中kset是什么意思,Linux内核之设备驱动-底层数据结构kobject/kset

    Linux内核之设备驱动-底层数据结构kobject/kset kobject kobject是组成device.driver.bus.class的基本结构.如果把前者看成基类,则后者均为它的派生产物 ...

最新文章

  1. 一致性协议算法-2PC、3PC、Paxos、Raft、ZAB、NWR超详细解析
  2. postergresql mysql_PosttgreSQL快速入门:PostgreSQL的安装和配置
  3. 谷歌X实验室的“无用”发明
  4. SharpDevelop 5.1 调试一个简单会员管理系统
  5. torch_geometric 笔记:TORCH_GEOMETRIC.UTILS(更新中)
  6. 解决 VSCode 编写 C++11 代码报红问题
  7. 育果医生CEO马于堃:互联网医疗行业与产品的本质
  8. 【送书活动】机器学习项目开发实战
  9. Mac OS 查看系统版本信息/硬件信息的命令
  10. tensorflow中的Supervisor
  11. Android Input子系统-含实例源码
  12. 在codeigniter中使用Cache_Lite来缓存
  13. java正方形个圆形面积_java计算图形面积(圆形,正方形, 长方形).pptx
  14. linux nightshift调整,iOS9.3夜间模式怎么设置?iOS9.3 Night Shift设置教程
  15. 疫情期间,找工作的一些建议
  16. For菜鸟文章:PE文件格式,qduwg翻译
  17. springboot基于微信小程序的宿舍管理系统
  18. 算法-求数组的子数组之和的最大值
  19. KVM远程迁移启动报错
  20. JVM垃圾回收机制及算法

热门文章

  1. python执行Linux命令sudo命令
  2. js的constructor和prototype
  3. 微服务中数据聚合的三种方式
  4. Ubuntu安装和配置ssh教程
  5. Mysql修改常用sql: 添加字段、修改字段、添加索引
  6. 【Java进阶】02-线程(中)
  7. AppStore 关于账号授权
  8. 美国2003-2015年道路交通事故数据及毕业论文
  9. Http协议及各版本对比
  10. linux下全盘查找文件,linux下的查找文件命令find