Linux设备驱动工程师之路——触摸屏驱动s3c2410_ts.c分析


一、触摸屏硬件知识

1.模块原理图

S3C2440有8路的ADC通道其中触摸屏控制器接口XP,XM,YP,YM与四路ADC通道复用四个IO引脚。从原理图看出8路ADC只有一个A/D转换器,通过一个8选1开关MUX来选通哪一路A/D通道进行转换。触摸屏控制会产生两个中断,一个触摸屏中断INT_ADC,一个ADC_转换完成中断INT_ADC。ADC需要时钟才能工作,因为它需要设置采样率。


再复习一下ARM裸机实验时触摸屏寄存器操作流程

流程:

         初始化

         1设置采样延时和分频值ADCDLY ADCCON

         2中断相关设置

         3设置触摸屏AD转换为等待中断模式 ADCTSC

         中断服务函数

         4清相关挂起寄存器

         5设置转换模式,一般为连续x,y转换

6 启动转换

          7 转换完成后读取x y坐标ADCDAT0ADCDAT1

          8 设置触摸屏AD转换为等待中断模式,设置等待弹起中断ADCTSC

9 弹起中断发生后,设置触摸屏转换为等待中断模式,等待下一次触笔按下rADCTSC

         程序

二、触摸屏驱动程序

1.模块初始化

  1. static int __init s3c2410ts_init(void)  
  2. {  
  3.     struct input_dev *input_dev;  
  4.   
  5.     //获取时钟  
  6.     adc_clock = clk_get(NULL, "adc");  
  7.     if (!adc_clock) {  
  8.         printk(KERN_ERR "failed to get adc clock source\n");  
  9.         return -ENOENT;  
  10.     }  
  11.     clk_enable(adc_clock);  
  12.     //使能时钟  
  13.     //需要时钟的是因为触摸屏要用到ADC转换,而完成ADC转换则需要时钟(采用时间)  
  14.   
  15.     //映射ADC的IO内存  
  16.     base_addr=ioremap(S3C2410_PA_ADC,0x20);  
  17.     if (base_addr == NULL) {  
  18.         printk(KERN_ERR "Failed to remap register block\n");  
  19.         return -ENOMEM;  
  20.     }  
  21.   
  22.     //初始化触摸屏的IO引脚  
  23.     /* Configure GPIOs */  
  24.     s3c2410_ts_connect();  
  25.   
  26.     //设置预分频值  
  27.     iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\  
  28.              base_addr+S3C2410_ADCCON);  
  29.     iowrite32(0xffff,  base_addr+S3C2410_ADCDLY);//设置采用延时  
  30.     iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);  
  31. //设置触摸屏控制器为等待按下中断  
  32.   
  33.     /* Initialise input stuff */  
  34.     //申请一个input设备  
  35.     input_dev = input_allocate_device();  
  36.   
  37.     if (!input_dev) {  
  38.         printk(KERN_ERR "Unable to allocate the input device !!\n");  
  39.         return -ENOMEM;  
  40.     }  
  41.   
  42.     dev = input_dev;  
  43.       
  44.     //设置可被支持的事件为同步、按键、绝对坐标事件  
  45. dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);  
  46. //设置按键时间类型为触摸屏  
  47.     dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);  
  48.   
  49.     //设置事件数值范围X,Y坐标范围为0到3FF,按键数值范围从0,到1  
  50.     input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);  
  51.     input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);  
  52.     input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);  
  53.   
  54.     //设置设备的身份信息  
  55.     dev->name = s3c2410ts_name;  
  56.     dev->id.bustype = BUS_RS232;  
  57.     dev->id.vendor = 0xDEAD;  
  58.     dev->id.product = 0xBEEF;  
  59.     dev->id.version = S3C2410TSVERSION;  
  60.   
  61.   
  62.     /* Get irqs */  
  63.     //获取触摸屏中断IRQ_TC,ADC转换完成中断IRQ_ADC  
  64.     if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,  
  65.         "s3c2410_action", dev)) {  
  66.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");  
  67.         iounmap(base_addr);  
  68.         return -EIO;  
  69.     }  
  70.     if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,  
  71.             "s3c2410_action", dev)) {  
  72.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");  
  73.         iounmap(base_addr);  
  74.         return -EIO;  
  75.     }  
  76.   
  77.     printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);  
  78.   
  79.     /* All went ok, so register to the input system */  
  80.     //注册设备  
  81.     input_register_device(dev);  
  82.   
  83.     return 0;  
  84. }  

我们再来看看模块初始化函数中初始化触摸屏的IO引脚的s3c2410_ts_connect();函数

  1. static inline void s3c2410_ts_connect(void)  
  2. {  
  3.     s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);  
  4.     s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);  
  5.     s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);  
  6.     s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);  
  7. }  

触摸屏控制器接口是与IO端口复用的。

2.触摸屏中断服务函数

  1. static irqreturn_t stylus_updown(int irq, void *dev_id)  
  2. {  
  3.     unsigned long data0;  
  4.     unsigned long data1;  
  5.     int updown;  
  6.   
  7.     if (down_trylock(&ADC_LOCK) == 0) {  
  8.         OwnADC = 1;  
  9.   
  10.         //读取ADCDAT0和ADCDAT1寄存器,判断是按下中断还是弹起中断  
  11.         //ADCDAT0和ADCDAT1查手册可知其第15位当按下时为0,弹起为1  
  12.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);  
  13.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);  
  14.   
  15.         updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));  
  16.   
  17.         if (updown) {  
  18.             touch_timer_fire(0);//当判断为按下时  
  19.         } else {  
  20.             OwnADC = 0;  
  21.             up(&ADC_LOCK);  
  22.         }  
  23.     }  
  24.   
  25.     return IRQ_HANDLED;  
  26. }  
  • 1
  • 2
  • 下一页

相关内容