zoukankan      html  css  js  c++  java
  • 触摸屏驱动分析和编程

    一、触摸屏驱动分析
    1. static int __init tq2440ts_init(void)
    2. {
    3.     struct input_dev *input_dev;

    4.     adc_clock = clk_get(NULL, "adc");
    5.     if (!adc_clock)
    6.     {
    7.         printk(KERN_ERR "failed to get adc clock source ");
    8.         return -ENOENT;
    9.     }
    10.     clk_enable(adc_clock);                                                          //使能ADC时钟

    11.     base_addr=ioremap(S3C2410_PA_ADC,0x20);                                         //将物理基地址转化成虚拟地址
    12.     if (base_addr == NULL)
    13.     {
    14.         printk(KERN_ERR "Failed to remap register block ");
    15.         return -ENOMEM;
    16.     }

    17.     /* Configure GPIOs */
    18. //    tq2440_ts_connect();

    19.     iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);            //设置寄存器
    20.     iowrite32(0xffff, base_addr+S3C2410_ADCDLY);
    21.     iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

    22.     /* Initialise input stuff */
    23.     input_dev = input_allocate_device();                                                //分配输入设备

    24.     if (!input_dev)
    25.     {
    26.         printk(KERN_ERR "Unable to allocate the input device !! ");
    27.         return -ENOMEM;
    28.     }

    29.     dev = input_dev;
    30.     dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);                             //设置可能的上报事件(同步信息)(按键信息)(abs是坐标)
    31.     dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
    32.     input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
    33.     input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
    34.     input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);

    35.     dev->name = tq2440ts_name;                                                           //填充一些设备信息
    36.     dev->id.bustype = BUS_RS232;
    37.     dev->id.vendor = 0xDEAD;
    38.     dev->id.product = 0xBEEF;
    39.     dev->id.version = S3C2410TSVERSION;

    40.     if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, tq2440ts_name, dev))                      //注册ADC中断处理程序
    41.     {
    42.         printk(KERN_ERR "tq2440_ts.c: Could not allocate ts IRQ_ADC ! ");
    43.         iounmap(base_addr);
    44.         return -EIO;
    45.     }
    46.     if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, tq2440ts_name, dev))                                   //注册TOUCH_SCREEN中断
    47.     {
    48.         printk(KERN_ERR "tq2440_ts.c: Could not allocate ts IRQ_ADC ! ");
    49.         iounmap(base_addr);
    50.         return -EIO;
    51.     }

    52.     printk(KERN_INFO "%s successfully loaded ", tq2440ts_name);

    53.     input_register_device(dev);                                                                     //注册输入型设备

    54.     return 0;
    55. }
    在手按下触摸屏时,会触发TC中断,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.     if (down_trylock(&ADC_LOCK) == 0)                                                                               //通过锁保护起来
    7.     {
    8.         OwnADC = 1;
    9.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);                                                                //读取寄存器
    10.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    11.         updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));                         //判断按下还是弹起

    12.         if (updown)                                                                                     //按下
    13.         {
    14.             touch_timer_fire(0);                                                                        //采样
    15.         }
    16.         else
    17.         {
    18.             OwnADC = 0;
    19.             up(&ADC_LOCK);                                                                               //释放锁
    20.         }
    21.     }

    22.     return IRQ_HANDLED;
    23. }
    touch_timer_fire():
    1. static void touch_timer_fire(unsigned long data)
    2. {
    3.       unsigned long data0;
    4.       unsigned long data1;
    5.     int updown;

    6.       data0 = ioread32(base_addr+S3C2410_ADCDAT0);
    7.       data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    8.      updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

    9.      if (updown) {
    10.          if (count != 0)                                                                                                               //如果count不是0,4次AD转换后进入
    11.          {
    12.             long tmp;
    13.                                                                                                  
    14.             tmp = xp;
    15.             xp = yp;
    16.             yp = tmp;
    17.                                                                                                  
    18.                         xp >>= 2;                                                                                                       //这是取平均值
    19.                         yp >>= 2;

    20.              input_report_abs(dev, ABS_X, xp);                                                                                          //可以上报XY坐标了
    21.              input_report_abs(dev, ABS_Y, yp);

    22.              input_report_key(dev, BTN_TOUCH, 1);                                                                                       //上报按键
    23.              input_report_abs(dev, ABS_PRESSURE, 1);                                                                                    //上报ABS按下
    24.              input_sync(dev);                                                                                                           //上报结束
    25.          }

    26.          xp = 0;
    27.          yp = 0;
    28.          count = 0;

    29.          iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);                                                  //启动xy转换
    30.          iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
    31.      }
    32.      else
    33.      {
    34.          count = 0;

    35.          input_report_key(dev, BTN_TOUCH, 0);
    36.          input_report_abs(dev, ABS_PRESSURE, 0);
    37.          input_sync(dev);

    38.          iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
    39.         if (OwnADC)
    40.         {
    41.             OwnADC = 0;
    42.             up(&ADC_LOCK);
    43.         }
    44.      }
    45. }
    调用adc中断(stylus_action):
    1. static irqreturn_t stylus_action(int irq, void *dev_id)
    2. {
    3.     unsigned long data0;
    4.     unsigned long data1;

    5.     if (OwnADC)
    6.     {
    7.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);
    8.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    9.         xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;                                                     //获取X、Y坐标
    10.         yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
    11.         count++;

    12.         if (count < (1<<2))                                                                            //count<4,意味着获取了4次
    13.         {
    14.             iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
    15.             iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
    16.         }
    17.         else
    18.         {
    19.             mod_timer(&touch_timer, jiffies+1);                                                          //启动内核定时器,1个时间就调用touch_timer
    20.             iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
    21.         }
    22.     }

    23.     return IRQ_HANDLED;
    24. }
    touch_timer:
    1. static struct timer_list touch_timer =
    2.         TIMER_INITIALIZER(touch_timer_fire, 0, 0);                                       //又调用了touch_timer_fire,不过此时count是4了

    二、触摸屏驱动编程

    1. static void touch_timer_fire(unsigned long data)
    2. {
    3.       unsigned long data0;
    4.       unsigned long data1;
    5.     int updown;

    6.       data0 = ioread32(base_addr+S3C2410_ADCDAT0);
    7.       data1 = ioread32(base_addr+S3C2410_ADCDAT1);

    8.      updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

    9.      if (updown) {
    10.             if(count != 0)
    11.             {
    12.                 long tmp;
    13.                 /*交换XY坐标*/
    14.                 tmp = xp;
    15.                 xp = yp;
    16.                 yp = tmp;
    17.                 /*除以4*/
    18.                 xp >>= 2;
    19.                 yp >>= 2;
    20.                 /*上报XY坐标*/
    21.                 input_report_abs(dev, ABS_X, xp);
    22.                 input_report_abs(dev, ABS_Y, yp);
    23.                 
    24.                 input_report_key(dev, BTN_TOUCH, 1);
    25.                 input_report_abs(dev, ABS_PRESSURE, 1);
    26.                 input_sync(dev);
    27.                  
    28.                 printk("x=%d,y=%d ",xp,yp);
    29.             }
    30.             
    31.             xp = 0;
    32.             yp = 0;

    33.             count = 0;
    34.             /*1.启动自动转换*/
    35.             iowrite32(1<<2, base_addr+S3C2410_ADCTSC);
    36.             iowrite32((ioread32(base_addr+S3C2410_ADCCON)|1<<0), base_addr+S3C2410_ADCCON);

    37.      }
    38.      else
    39.      {
    40.          count = 0;

    41.          input_report_key(dev, BTN_TOUCH, 0);
    42.          input_report_abs(dev, ABS_PRESSURE, 0);
    43.          input_sync(dev);

    44.          iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
    45.         if (OwnADC)
    46.         {
    47.             OwnADC = 0;
    48.             up(&ADC_LOCK);
    49.         }
    50.      }
    51. }

    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    PHP7中php.ini、php-fpm和www.conf的配置(转)
    Linux下查看nginx、mysql、php的安装路径和编译参数
    Skip List(跳跃表)原理详解与实现【转】
    offset宏的讲解【转】
    Linux内核中的常用宏container_of其实很简单【转】
    Linux内核同步原语之原子操作【转】
    创建与合并分支【转】
    Git远程操作详解【转】
    【项目管理】git和码云的使用【转】
    Git和Github简单教程【转】
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363299.html
Copyright © 2011-2022 走看看