歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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. }  
Copyright © Linux教程網 All Rights Reserved