移植ads7846驱动到tiny6410(tiny6410)

摘要:

       目前,市面上很多6410开发板都存在触摸屏抖动的问题,tiny6410也不例外,友善的解决方法是采用一线触摸,即在LCD板上,用一个单片机控制ADS7846芯片AD转换,再将数据通过单总线的方式与6410通讯。可是,我这里没有一线触摸板,于是就开始移植ADS7846驱动到tiny6410。

介绍:

        可能有人会问,6410的触摸屏为什么会抖动呢,是不是滤波没做好,或者是硬件走线的原因?是不是硬件的原因,我无法验证。我尝试过通过滤波来改善,但效果一般。不说别的,我在单独测试AD的时候,发现在输入不变的情况下,AD采样的跳幅最大达到25(0~1024范围),可见,跳动还是很大的,这样的情况下,即使再滤波也只是浪费时间。

        mini6410-ts.c触摸屏驱动见:

       (原创)6410触摸屏驱动分析(s3c-ts.c)(Linux)(分析)

        先说说我的硬件:

            TS_PEN   ----- GPN9   EINT9

            TS_MISO  ----  GPC0   MISO0

            TS_MOSI  ----   GPC2  MOSI0

            TS_SCK    -----  GPC1  SCK0

            TS_CS      -----  GPC3   CS0

           这些端子在核心板的CON1上可以找到,我这里是用的IO模拟的SPI。

        下面的开始介绍移植的过程,代码,我在下面会全部帖出来,里面注释也很详细,一般都能看明白。

         1、复制/opt/FriendlyARM/mini6410/linux-2.6.38/drivers/input/touchscreen/mini6410-ts.c为mini6410-ads7846.c。

         修改后,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
/* linux/drivers/input/touchscreen/s3c-ts.c
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  * a misc driver for mini6410 touch screen
  *  by FriendlyARM 2010
  *
  * Based on following software:
  *
  ** Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
  ** iPAQ H1940 touchscreen support
  **
  ** ChangeLog
  **
  ** 2004-09-05: Herbert Potzl <herbert@13thfloor.at>
  ** - added clock (de-)allocation code
  **
  ** 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
  **      - h1940_ -> s3c24xx (this driver is now also used on the n30
  **        machines :P)
  **      - Debug messages are now enabled with the config option
  **        TOUCHSCREEN_S3C_DEBUG
  **      - Changed the way the value are read
  **      - Input subsystem should now work
  **      - Use ioremap and readl/writel
  **
  ** 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
  **      - Make use of some undocumented features of the touchscreen
  **        controller
  **
  ** 2006-09-05: Ryu Euiyoul <ryu.real@gmail.com>
  **      - added power management suspend and resume code
  *
  * 2011-6-23: ADS7846触摸屏驱动程序 by liu_xf
  *           http://www.cnblogs.com/liu_xf
  *
  * 2011-6-29 改进滤波,并将AD连续转换8次的间隔缩小了
  */
 
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
 
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <mach/hardware.h>
 
 
//#include <mach/irqs.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio-bank-n.h>
#include <mach/gpio-bank-c.h>
 
 
#define CONFIG_TOUCHSCREEN_ADS7846_DEBUG
#undef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
#define DEBUG_LVL       KERN_DEBUG
 
 
/*
  * Definitions & global arrays.
  */
#define DEVICE_NAME     "touchscreen"
static  DECLARE_WAIT_QUEUE_HEAD(ts_waitq); //定义并初始化一个等待队列
 
typedef  unsigned        TS_EVENT;
#define NR_EVENTS       64     //触摸屏fifo大小
 
 
static  TS_EVENT         events[NR_EVENTS];
static  int               evt_head, evt_tail; //fifo的头的尾
                                                             //驱动写fifo时evt_head++,应用读fifo时 evt_tail++
 
#define ts_evt_pending()    ((volatile u8)(evt_head != evt_tail))   //相等就表示满了
#define ts_evt_get()        (events + evt_tail)
#define ts_evt_pull()       (evt_tail = (evt_tail + 1) & (NR_EVENTS - 1))
#define ts_evt_clear()      (evt_head = evt_tail = 0)
 
#define ADS7846_CNV_NBR  8  //ADC连续转换的次数
struct  ads7846_ts_info {
 
     struct  input_dev *dev;
 
     unsigned int  xp; //x方向位置
     unsigned int  yp; //y方向位置
     unsigned int  count; //adc转换次数
     unsigned int  cnv_nbr;
     unsigned int  x_buf[ADS7846_CNV_NBR];  //ad转换buf
     unsigned int  y_buf[ADS7846_CNV_NBR];
     
};
 
static  struct  ads7846_ts_info   *ts;
 
 
 
 
//ADS7846底层操作========================================================================
#define ADS7846_GPIO_MISO   0   //gpc0
#define ADS7846_GPIO_MOSI   2     //gpc2
#define ADS7846_GPIO_CLK   1       //gpc1
#define ADS7846_GPIO_CS   3       //gpc3
 
// ADS7846 Control Byte bit defines
#define ADS7846_CMD_START   0x0080
#define ADS7846_ADDR_BIT    4
#define ADS7846_ADDR_MASK   (0x7<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_X   (0x5<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Y   (0x1<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Z1  (0x3<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Z2  (0x4<<ADS7846_ADDR_BIT)
#define ADS7846_8BITS       (1<<3)
#define ADS7846_12BITS      0
#define ADS7846_SER         (1<<2)
#define ADS7846_DFR         0
#define ADS7846_PWR_BIT     0
#define ADS7846_PD          0
#define ADS7846_ADC_ON      (0x1<<ADS7846_PWR_BIT)
#define ADS7846_REF_ON      (0x2<<ADS7846_PWR_BIT)
#define ADS7846_REF_ADC_ON  (0x3<<ADS7846_PWR_BIT)
 
#define MEASURE_8BIT_X\
     (unsigned short )(ADS7846_CMD_START | ADS7846_MEASURE_X | ADS7846_8BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_8BIT_Y\
     (unsigned short )(ADS7846_CMD_START | ADS7846_MEASURE_Y | ADS7846_8BITS | ADS7846_DFR | ADS7846_PD)
 
#define MEASURE_12BIT_X \
     (unsigned short )(ADS7846_CMD_START | ADS7846_MEASURE_X | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Y \
     (unsigned short )(ADS7846_CMD_START | ADS7846_MEASURE_Y | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Z1 \
     (unsigned char )(ADS7846_MEASURE_Z1 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Z2 \
     (unsigned char )(ADS7846_MEASURE_Z2 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
     
// Pin access
//
static  inline  void  set_miso_as_up( void ) //gpc0
{
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCPUD);
     tmp &= ~(3U <<0);
     tmp |= (2U << 0);
     writel(tmp, S3C64XX_GPCPUD);
}
 
static  inline  void  set_miso_as_input( void ) //gpc0
{
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCCON);
     tmp &= ~(0xf << 0);
     writel(tmp, S3C64XX_GPCCON);
}
 
static  inline  void  set_cs_mosi_clk_as_output( void ) //gpc1 2 3
{
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCCON);
     tmp = (tmp & ~0xfff0) | (0x1110);
     writel(tmp, S3C64XX_GPCCON);
}
 
static  inline  void  set_cs_mosi_clk_as_up( void ) //gpc1 2 3
{
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCPUD);
     tmp &= ~((3U <<2)|(3U <<4)|(3U <<6));
     tmp |= (2U << 2) | (2U << 4) | (2U << 6);
     writel(tmp, S3C64XX_GPCPUD);
}
 
 
static  inline  void  set_gpcx_value( int  pinx , int  v)
{
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCDAT);
     if  (v) {
         tmp |= (1 << pinx);
     } else  {
         tmp &= ~(1<<pinx);
     }
     writel(tmp, S3C64XX_GPCDAT);
}
 
static  inline  int  get_gpcx_value( int  pinx)
{
     int  v;
     unsigned long  tmp;
     tmp = readl(S3C64XX_GPCDAT);
     v = !!(tmp & (1<<pinx));
     return  v;
}
 
//读12bit
static  unsigned int  ads7846_Read_Data( void )
{
  unsigned int  i,temp=0x00;
    for (i=0;i<12;i++)
    {
        temp <<=1;
        set_gpcx_value(ADS7846_GPIO_CLK, 1); udelay(10);
        set_gpcx_value(ADS7846_GPIO_CLK, 0); udelay(10);
        if (get_gpcx_value(ADS7846_GPIO_MISO) != 0)temp++;
    }
    return  (temp);
}
//写8bit
static  void  ads7846_Write_Data(unsigned int  n)
{
    unsigned char  i;
   set_gpcx_value(ADS7846_GPIO_CLK, 0);
   for (i=0;i<8;i++)
    {
     if ((n&0x80)==0x80)
       set_gpcx_value(ADS7846_GPIO_MOSI, 1);
      else
       set_gpcx_value(ADS7846_GPIO_MOSI, 0);
     
     n <<= 1;
     set_gpcx_value(ADS7846_GPIO_CLK, 1);  udelay(10);
     set_gpcx_value(ADS7846_GPIO_CLK, 0); udelay(10);
     }
}
 
 
//ADS7846转换==
//保存在ts->buf 当中
static  void  ads7846_conver_start( void )
{
     int  i;
     unsigned int  cmd[2];
     unsigned int  data[2];
         
     set_gpcx_value(ADS7846_GPIO_CS, 0);
         //开读
     cmd[0] = MEASURE_12BIT_X;
     cmd[1] = MEASURE_12BIT_Y;
 
     /* CS# Low */
     set_gpcx_value(ADS7846_GPIO_CS, 0);
     
     //连续转换
     for (ts->count=0; ts->count<ts->cnv_nbr;)
     {
         //分别读出x y坐标==
         for (i=0; i<2; i++){
           ads7846_Write_Data(cmd[i]);
           udelay(40);
           data[i] = ads7846_Read_Data();
         }
         
         
 
         //保存转换结果
         ts->x_buf[ts->count]= data[0];
         ts->y_buf[ts->count]= data[1];
         ts->count++;
     }
     /* CS# High */
     set_gpcx_value(ADS7846_GPIO_CS, 1);
 
#ifdef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
     //printk("ts read pos: x = %d, y = %d\n", data[0], data[1]);
#endif
     
}
 
 
//-----------------------------------------------------------------------------
 
//触摸屏数据滤波算法
//触摸屏AD连续转换N次后,按升序排列,再取中间几位值求平均
#define  TS_AD_NBR_PJ    4       //取中间4位求平均值
#define  TS_AD_NBR_MAX_CZ    10       //最大与最小的差值
static  inline  bool  touch_ad_data_filter(unsigned int  *buf0, unsigned int  *buf1)
{
    unsigned int  i,j,k,temp,temp1,nbr=(ADS7846_CNV_NBR);
    //将转换结果升序排列
    //buf0
     for  (j= 0; j< nbr; j++)
     for  (i = 0; i < nbr; i++)
     {          
         if (buf0[i]>buf0[i+1]) //升序排列
     {
         temp=buf0[i+1];
         buf0[i+1]=buf0[i];
         buf0[i]=temp;
    
     }
   
     //buf1
     for  (j= 0; j< nbr; j++)
     for  (i = 0; i < nbr; i++)
     {          
         if (buf1[i]>buf1[i+1]) //升序排列
     {
         temp=buf1[i+1];
         buf1[i+1]=buf1[i];
         buf1[i]=temp;
    
     }
  
     //串口调试查看结果
     //for (j= 0; j< nbr; j++)
      // printk("buf0[%2d]=%4d, buf1[%2d]=%4d,\r\n",j,buf0[j],j,buf1[j]);
    //取中间值求平均==
    k=((nbr-TS_AD_NBR_PJ)>>1);
    temp = 0;temp1 = 0;
    //检查值是否有效==
    if ((buf0[k+TS_AD_NBR_PJ-1]-buf0[k]>TS_AD_NBR_MAX_CZ)||(buf1[k+TS_AD_NBR_PJ-1]-buf1[k]>TS_AD_NBR_MAX_CZ)) //无效值
     {
 
       return  0;
     }
    //--
    //将中间指定位数累加
    for (i=0;i<TS_AD_NBR_PJ;i++)
   
       temp += buf0[k+i];
       temp1 += buf1[k+i];
    }
    //求平均值,将结果保存在最低位
    buf0[0]=temp/TS_AD_NBR_PJ;  
    buf1[0] = temp1/TS_AD_NBR_PJ;
    //--
    return  1;
    
}
 
 
//将AD转换的值放入FIFO
//这里是一个先进先出的fifo
//只要有数据被添加进来,就会唤醒ts_waitq进程
static  void  ts_evt_add(unsigned x, unsigned y, unsigned down) {
     unsigned ts_event;
     int  next_head;
 
     ts_event = ((x << 16) | (y)) | (down << 31);
     next_head = (evt_head + 1) & (NR_EVENTS - 1);
         //没满就装入
     if  (next_head != evt_tail) {
         events[evt_head] = ts_event;
         evt_head = next_head;
#ifdef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
         printk( "====>Add ... [ %4d,  %4d ]%s\n" , x, y, down ? "" : " ~~~" );
#endif
         /* wake up any read call */
         if  (waitqueue_active(&ts_waitq)) { //判斷等待隊列是否有進程睡眠
             wake_up_interruptible(&ts_waitq);  //唤醒ts_waitq等待队列中所有interruptible类型的进程
         }
     } else  {
         /* drop the event and try to wakeup readers */
         printk(KERN_WARNING "mini6410-ads7846: touch event buffer full" );
         wake_up_interruptible(&ts_waitq);
     }
}
 
static  unsigned int  ads7846_ts_poll( struct  file *file, struct  poll_table_struct *wait)
{
     unsigned int  mask = 0;
 
     //将ts_waitq等待队列添加到poll_table里去
     poll_wait(file, &ts_waitq, wait);
     //返回掩码                                 
     if  (ts_evt_pending())
         mask |= POLLIN | POLLRDNORM;  //返回设备可读
 
     return  mask;
}
 
//读 系统调用==
static  int  ads7846_ts_read( struct  file *filp, char  __user *buff, size_t  count, loff_t *offp)
{
     DECLARE_WAITQUEUE(wait, current); //把当前进程加到定义的等待队列头wait中
     char  *ptr = buff;
     int  err = 0;
 
     add_wait_queue(&ts_waitq, &wait); //把wait入到等待队列头中。该队列会在进程等待的条件满足时唤醒它。
                                       //我们必须在其他地方写相关代码,在事件发生时,对等的队列执行wake_up()操作。
                                       //这里是在ts_evt_add里wake_up
     while  (count >= sizeof (TS_EVENT)) {
         err = -ERESTARTSYS;
         if  (signal_pending(current)) //如果是信号唤醒    参考http://www.360doc.com/content/10/1009/17/1317564_59632874.shtml
             break ;
 
         if  (ts_evt_pending()) {
             TS_EVENT *evt = ts_evt_get();
 
             err = copy_to_user(ptr, evt, sizeof (TS_EVENT));
             ts_evt_pull();
 
             if  (err)
                 break ;
 
             ptr += sizeof (TS_EVENT);
             count -= sizeof (TS_EVENT);
             continue ;
         }
 
         set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为可中断的睡眠
         err = -EAGAIN;
         if  (filp->f_flags & O_NONBLOCK) //如果上层调用是非阻塞方式,则不阻塞该进程,直接返回EAGAIN
             break ;
         schedule();  //本进程在此处交出CPU控制权,等待被唤醒
                       //进程调度的意思侧重于把当前任务从CPU拿掉,再从就绪队列中按照调度算法取一就绪进程占用CPU
     }
     current->state = TASK_RUNNING;
     remove_wait_queue(&ts_waitq, &wait);
 
     return  ptr == buff ? err : ptr - buff;
}
//--
 
static  int  ads7846_ts_open( struct  inode *inode, struct  file *filp) {
     /* flush event queue */
     ts_evt_clear();
 
     return  0;
}
 
//当应用程序操作设备文件时调用的open read等函数,最终会调用这个结构体中对应的函数
static  struct  file_operations dev_fops = {
     .owner              = THIS_MODULE,
     .read               = ads7846_ts_read,
     .poll               = ads7846_ts_poll,  //select系统调用
     .open               = ads7846_ts_open,
};
 
//设备号,设备名,注册的时候用到这个数组
//混杂设备主设备号为10
static  struct  miscdevice misc = {
         .minor              = MISC_DYNAMIC_MINOR, //自动分配次设置号
     //.minor                = 180,
     .name               = DEVICE_NAME,
     .fops               = &dev_fops,
};
 
 
 
 
 
 
/**
  * get_down - return the down state of the pen
  * 获取pen引脚状态,为0表示down
  * GPN9 EINT9 TS_PEN
  */
static  inline  bool  get_down( void )
{
    int  tmp,down;
    tmp = readl(S3C64XX_GPNDAT);
    down = !(tmp & (1<<9));
     return  (down); 
}
 
 
/*===========================================================================================
     touch_timer_get_value这个函数的调用:
     
     1、  触摸笔开始点击的时候, 在中断函数touch_down里面被调用,不是直接调用,而是设置定时器超时后调用
          这样是为了去抖动
          
     2、  touch_timer_get_value被调用一次后,如果pendown信号有效,则touch_timer_get_value会被持续调用
          也是通过定时器实现的
          
     touch_timer_get_value这个函数的功能:
       启动7846转换,直到连续转换8次后,再滤波处理,获得有效值,并向上报告触摸屏事件
 
============================================================================================*/
static  void  touch_timer_get_value(unsigned long  data);
 
static  DEFINE_TIMER(touch_timer, touch_timer_get_value, 0, 0);
 
static  void  touch_timer_get_value(unsigned long  data) {
 
     int  pendown;
        
     pendown = get_down();
 
#ifdef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
//  if(pendown)
//  { 
//    printk("touch is down!\n");
//  }
//  else
//    printk("touch is up!\n");
#endif
     
     if  (pendown) {
 
             //关中断===
            disable_irq(IRQ_EINT(9));
            //--
            //启动ADS7846转换==
             ads7846_conver_start();
          //开中断==
              enable_irq(IRQ_EINT(9));
              //--
         //如果转换了8次,就写入FIFO保存
         //if (ts->count == ( ts->cnv_nbr)) { 
             if (touch_ad_data_filter(ts->x_buf,ts->y_buf)) //滤波处理
                        {
                 
             ts->xp = ts->x_buf[0];
             ts->yp = ts->y_buf[0];
             
             ts_evt_add(ts->xp, ts->yp, 1);  //向上报告触摸屏事件
                }
                
 
             ts->xp = 0;
             ts->yp = 0;
             ts->count = 0;
         //}
                 //--
                
         mod_timer(&touch_timer, jiffies + 2);   //重新设置系统定时器,超时后,又会调用touch_timer_get_value
                                                  //jiffies变量记录了系统启动以来,系统定时器已经触发的次数。内核每秒钟将jiffies变量增加HZ次。
                                                 //因此,对于HZ值为100的系统,1个jiffy等于10ms,而对于HZ为1000的系统,1个jiffy仅为1ms
                                                 //这里系统配置提HZ是100
         
     } else  //如果是松开,报告其触摸笔状态
         ts->xp = 0;
         ts->yp = 0;
         ts->count = 0;
 
         ts_evt_add(0, 0, 0);
 
 
     }
     
}
 
 
 
//触摸屏按下中断服务==
//双边沿中断
static  irqreturn_t touch_down( int  irqno, void  *param)
{
        
       
     /* Clear  interrupt */
     //__raw_writel(0x0, ts_base + S3C_ADCCLRWK);
     //__raw_writel(0x0, ts_base + S3C_ADCCLRINT);
 
         //稍后调用touch_timer_get_value,去抖动
     mod_timer(&touch_timer, jiffies + 2);  //等ADS7846转换完成了再读
                                             //同时还可以防抖动,如果定时器没有超时的这段时间里,发生了抬起和按下中断,则定时器的值会被重设,不会超时
                                             //内核配置时HZ值设为100,即1个jiffy等于10ms,
     //touch_timer_get_value(1);  //直接调用会有抖动
 
     return  IRQ_RETVAL(IRQ_HANDLED);
}
 
 
 
 
//-------------------------------------------
 
 
/*
  * The functions for inserting/removing us as a module.
  */
static  int  __init ads7846_ts_probe( struct  platform_device *pdev)
{
     struct  device *dev;
     int  ret = 0;
     
     dev = &pdev->dev;
#ifdef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
     printk( "ads7846_ts_probe start!\n" );
#endif   
     //给ads7846_ts_info指针分配内存==
     ts = kzalloc( sizeof ( struct  ads7846_ts_info), GFP_KERNEL);
     ts->cnv_nbr = ADS7846_CNV_NBR;
     ts->xp = 0;
     ts->yp = 0;
     ts->count = 0;
   
     
     //申请中断==
     //TS_PEN双边沿触发 EINT9  GPN9
     ret = request_irq(IRQ_EINT(9), touch_down,IRQ_TYPE_EDGE_BOTH,
                           "ads7864_touch" , ts);
 
     if  (ret != 0) {
         dev_err(dev, "ads7846_ts.c: Could not allocate ts IRQ_EINT !\n" );
         ret = -EIO;
         goto  fail;
     }
        
      
 
     
      ret = misc_register(&misc);  //注册这混杂字符设备
     if  (ret) {
         dev_err(dev, "ads7846_ts.c: Could not register device(mini6410 touchscreen)!\n" );
         ret = -EIO;
         goto  fail;
     }
     //初始化GPIO==
     set_miso_as_up();
     set_miso_as_input();
     set_cs_mosi_clk_as_up();
     set_cs_mosi_clk_as_output();
     set_gpcx_value(ADS7846_GPIO_MOSI ,1);  
     set_gpcx_value(ADS7846_GPIO_CS ,1);
     set_gpcx_value(ADS7846_GPIO_CLK ,1);
     //--
 
#ifdef CONFIG_TOUCHSCREEN_ADS7846_DEBUG
     printk( "ads7846_ts_probe end!\n" );
#endif   
     
     return  0;
 
fail:
     disable_irq(IRQ_EINT(9));
         free_irq(IRQ_EINT(9), ts);
 
     return  ret;
 
}
 
static  int  ads7846_ts_remove( struct  platform_device *dev)
{
     printk(KERN_INFO "ads7846_ts_remove() of TS called !\n" );
         
     disable_irq(IRQ_EINT(9));
         free_irq(IRQ_EINT(9), ts);
     return  0;
}
 
#ifdef CONFIG_PM
static  unsigned int  adccon, adctsc, adcdly;
 
static  int  ads7846_ts_suspend( struct  platform_device *dev, pm_message_t state)
{
 
     return  0;
}
 
static  int  ads7846_ts_resume( struct  platform_device *pdev)
{
     return  0;
}
#else
#define ads7846_ts_suspend  NULL
#define ads7846_ts_resume   NULL
#endif
 
static  struct  platform_driver ads7846_ts_driver = {
     .probe          = ads7846_ts_probe,
     . remove          = ads7846_ts_remove,
     .suspend        = ads7846_ts_suspend,
     .resume         = ads7846_ts_resume,
     .driver         = {
         .owner          = THIS_MODULE,
         .name           = "ads7846-ts" ,
     },
};
 
static  char  banner[] __initdata = KERN_INFO "mini6410 ads7846 Touchscreen driver,by liu_xf 20110622,\n" ;
 
static  int  __init ads7846_ts_init( void )
{
     printk(banner);
     return  platform_driver_register(&ads7846_ts_driver);
}
 
static  void  __exit ads7846_ts_exit( void )
{
     platform_driver_unregister(&ads7846_ts_driver);
}
 
module_init(ads7846_ts_init);
module_exit(ads7846_ts_exit);
 
MODULE_AUTHOR( "Hunan Create Inc." );
MODULE_LICENSE( "GPL" );

  2、修改当前目录下的Kconfig和makefile,让它在menuconfig里可见,并能被编译。

    在 Kconfig里添加:

?
1
2
3
4
5
6
7
8
9
10
11
12
config TOUCHSCREEN_MINI6410_ADS7846
     tristate "ADS7846 touchscreen driver for Mini6410"
     depends on MACH_MINI6410
     default  y
     help
       Say Y here to enable the driver for  the ADS7846 touchscreen on the
       FriendlyARM Mini6410 development board.
 
       If unsure, say N.
 
       To compile this  driver as a module, choose M here: the
       module will be called mini6410-ads7846.

     makefile里添加

?
obj-$(CONFIG_TOUCHSCREEN_MINI6410_ADS7846)  += mini6410-ads7846.o<br>

     3、  ads7846_device_ts设备定义

          复制 /opt/FriendlyARM/mini6410/linux-2.6.38/arch/arm/mach-s3c64xx/dev-ts-mini6410.c为dev-ads7846-mini6410.c,更改代码为

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/* linux/arch/arm/mach-s3c64xx/dev-ts-mini6410.c
  *
  * Copyright (c) 2008 Simtec Electronics
  *  Ben Dooks <ben@simtec.co.uk>
  *
  * S3C series device definition for touchscreen devices
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
*/
 
#include <linux/kernel.h>
#include <linux/platform_device.h>
 
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/devs.h>
#include <plat/cpu.h>
#include <mach/ts.h>
 
/* Touch srcreen */
//resource没有用,先留在这,不管它
static  struct  resource ads7846_ts_resource[] = {
     [0] = {
         .start = SAMSUNG_PA_ADC,
         .end   = SAMSUNG_PA_ADC + SZ_256 - 1,
         .flags = IORESOURCE_MEM,
     },
     [1] = {
         .start = IRQ_PENDN,
         .end   = IRQ_PENDN,
         .flags = IORESOURCE_IRQ,
     },
     [2] = {
         .start = IRQ_ADC,
         .end   = IRQ_ADC,
         .flags = IORESOURCE_IRQ,
     }
};
 
struct  platform_device ads7846_device_ts = {
     .name         = "ads7846-ts" ,
     .id       = -1,
     .num_resources    = ARRAY_SIZE(ads7846_ts_resource),
     .resource     = ads7846_ts_resource,
};
/*
void __init ads7846_ts_set_platdata(struct s3c_ts_mach_info *pd)
{
         printk(KERN_ERR "%s: no platform data\n", __func__);
     
}
*/

4、在/opt/FriendlyARM/mini6410/linux-2.6.38/arch/arm/mach-s3c64xx/mach-mini6410.c的platform_device添加ads7846_device_ts设备(s3c_device_ts附近),注册设备时要用到它

?
#ifdef CONFIG_TOUCHSCREEN_MINI6410_ADS7846
     &ads7846_device_ts,
#endif

5、添加设备声明

    mach-mini6410里注册ads7846_device_ts设备,但在哪里mach-mini6410并不知道,需要在devs.h里声明,打开当前目录下的devs.h,添加如下代码:


?
extern  struct  platform_device ads7846_device_ts;<br>

   6、然后再make,放到SD卡里运行

     make menuconfig,在device drives-> input   device support -> touch screens选择ADS7846 touchscreen driver for Mini6410 ,然后再make zImage。

     完成后,再放到SD卡里运行,怎么样,一点也不抖动了吧!

结语:

        这个驱动是由mini6410-ts.c修改而来的,那些系统调用的函数都没有改,只是将获取触摸屏数据的方式变了,可以直接用原来的tslib。经测试,效果良好。但是在移植的过程中,有一个问题还是没搞明白,之前,我是将TS_PEN接在EINT6上在的,但一接上去,就一直中断,把系统都弄死了,要按下触摸屏才能停止中断,不知道是什么原因,可能是EINT6被其它地方设置了,还是怎么回事,后来换成EINT9就好了,正好两个端子相邻。知道的大侠还请告诉我一声。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值