sep4020_tp.c
上传用户:shlb_js
上传日期:2022-08-10
资源大小:3k
文件大小:8k
源码类别:

驱动编程

开发平台:

C/C++

  1. /* linux/drivers/char/sep4020_char/sep4020_tp.c
  2.  *
  3. * Copyright (c) 2009 prochip company
  4. * http://www.prochip.com.cn
  5. * leeming1203@gmail.com.cn
  6. *
  7. * sep4020 touchpad driver.
  8. *
  9. * Changelog:
  10. * 22-jan-2009 leeming Initial version
  11. * 27-Apr-2009 leeming   fixed a lot
  12.  *
  13.  * 
  14.  *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 2 of the License, or
  18. * (at your option) any later version.
  19. */
  20. #include <linux/module.h>
  21. #include <linux/types.h>
  22. #include <linux/fs.h>
  23. #include <linux/errno.h>
  24. #include <linux/mm.h>
  25. #include <linux/sched.h>
  26. #include <linux/init.h>
  27. #include <linux/cdev.h>
  28. #include <linux/interrupt.h>
  29. #include <linux/time.h>
  30. #include <linux/spinlock_types.h>
  31. #include <linux/delay.h>
  32. #include <asm/types.h>
  33. #include <asm/system.h>
  34. #include <asm/uaccess.h>
  35. #include <asm/io.h>
  36. #include <asm/hardware.h>
  37. #include <asm/arch/sep4020_hal.h>
  38. #define TP_MAJOR        251 //主设备号 
  39. #define X_LOCATION_CMD  0x90 
  40. #define Y_LOCATION_CMD  0xd0 
  41. #define PEN_UP          0
  42. #define PEN_UNSURE      1 
  43. #define PEN_DOWN        2 
  44. #define PEN_TIMER_DELAY_JUDGE           2// judge whether the pendown message is a true pendown     jiffes
  45. #define PEN_TIMER_DELAY_LONGTOUCH       1// judge whether the pendown message is a long-time touch  jiffes
  46. #define CSL     CLR_BIT(TP1_DATA_PORT , TP1_BIT) //cs 片选信号拉低
  47. #define CSH     SET_BIT(TP1_DATA_PORT , TP1_BIT) //cs 片选信号拉高
  48. #define CLKL    CLR_BIT(TP2_DATA_PORT , TP2_BIT) //时钟输入口线
  49. #define CLKH    SET_BIT(TP2_DATA_PORT , TP2_BIT)
  50. #define DATAL   CLR_BIT(TP3_DATA_PORT , TP3_BIT) //命令输入口线
  51. #define DATAH   SET_BIT(TP3_DATA_PORT , TP3_BIT)
  52. static int s_tp_openflag = 0;
  53. static int s_pen_status  = PEN_UP;
  54. struct tp_dev
  55. {
  56.     struct cdev cdev;
  57.     unsigned short zpix;
  58.     unsigned short xpix;
  59.     unsigned short ypix;
  60.     struct timer_list tp_timer;
  61. };
  62. struct tp_dev *tpdev;//触摸屏结构体
  63.  static unsigned short PenSPIXfer(unsigned short ADCommd)
  64. {
  65.     unsigned short data=0; 
  66.     int i=0;
  67.     CSL;
  68.     udelay(10);
  69.         //前8个节拍发送命令
  70.     for(i = 0; i < 8; i++)
  71.     {
  72.     CLKL;
  73.     udelay(10);
  74.     if(ADCommd & 0x80) //从命令的最高位开始
  75.         {
  76.         DATAH;
  77.         }
  78.   else
  79.         {
  80.         DATAL;
  81.         }  
  82.     CLKH;
  83.     udelay(10);
  84.     ADCommd <<= 1;
  85.     }
  86.      //3个节拍以上的等待,保证控制命令的完成
  87.     udelay(50);
  88.         //12个节拍读取转换成数字信号的ad采样值
  89.     for(i=0;i<12;i++)
  90.         {
  91.     CLKL;
  92.     udelay(10);
  93.     if(GET_BIT(TP4_DATA_PORT,TP4_BIT))//判断数据输出位是否为1
  94.         {
  95.         data |= 0x1; 
  96. }
  97.     data <<= 1;
  98.     CLKH;
  99.     udelay(10);
  100.         }
  101. //3个节拍以上的等待,保证最后一位数据的完成
  102.     udelay(50);
  103.     CSH;
  104.     return data;    
  105.  
  106. }
  107. static void sep4020_tp_setup(void)
  108. {
  109.     *(volatile unsigned long*)INTC_IMR_V |= 0x200; //extern int 8
  110.     *(volatile unsigned long*)INTC_IER_V |= 0x200;  
  111.    
  112.    disable_irq(INTSRC_EXTINT8);
  113.       SET_PORT_MASK(TP5_SEL_PORT,TP5_MASK);   //通用用途
  114.    SET_PORT_MASK(TP5_DIR_PORT,TP5_MASK);  //输入 
  115.     CONFIG_INT(INTSRC_EXTINT8,LOW_LEVEL_TRIG);     
  116.    // *(volatile unsigned long*)GPIO_PORTA_INTRCTL_V |= 0x30000;             //低电平触发
  117.     //*(volatile unsigned long*)GPIO_PORTA_INCTL_V |= 0x100;                 //外部中断源输入
  118.        SET_PORT_MASK(TP6_DIR_PORT,TP6_MASK); //portD0 输入
  119.        CLR_PORT_MASK(TP7_DIR_PORT,TP7_MASK); //prortD1, portD3, portD4输出
  120.        SET_PORT_MASK(TP8_SEL_PORT,TP8_MASK); //0,1,3,4均设置为通用(普通io)
  121.    mdelay(20);
  122.     printk("in the touchpad setup n");
  123.      CLR_INT(TP_INT);
  124.     enable_irq(INTSRC_EXTINT8);
  125. static void tsevent(void)
  126. {
  127.     if (s_pen_status == PEN_DOWN) 
  128.         {
  129.         tpdev->xpix = PenSPIXfer(X_LOCATION_CMD);
  130.         tpdev->ypix = PenSPIXfer(Y_LOCATION_CMD);
  131.         tpdev->zpix = 0;  //0 means down;
  132.     }
  133.     else if(s_pen_status == PEN_UP)
  134.         {
  135.         tpdev->zpix = 4; //4 means up;
  136.     }
  137. }
  138. static void tp_timer_handler(unsigned long arg)
  139. {
  140.     int penflag = 0;
  141.    penflag = GET_PORT_MASK(TP9_DATA_PORT,TP9_MASK);   //读取中断口数值
  142.     if((penflag & 0x100) == 0)//如果第九位是低电平,表示触摸屏仍然被按着
  143.         {
  144.         if(s_pen_status == PEN_UNSURE )
  145.                          s_pen_status = PEN_DOWN;
  146.         tpdev->tp_timer.expires = jiffies + PEN_TIMER_DELAY_LONGTOUCH;
  147.         tsevent();      //读取触摸屏坐标
  148.         add_timer(&tpdev->tp_timer);
  149.         }
  150.     else
  151.         {
  152.         del_timer_sync(&tpdev->tp_timer);//在定时器到期前禁止一个已注册的定时器
  153.         s_pen_status = PEN_UP;
  154.         tsevent();
  155.          
  156.          CLR_INT(TP_INT);
  157.         enable_irq(INTSRC_EXTINT8);
  158.         }
  159. }
  160. static int sep4020_tp_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
  161.     disable_irq(INTSRC_EXTINT8); 
  162.     s_pen_status = PEN_UNSURE;
  163.     tpdev->tp_timer.expires = jiffies + PEN_TIMER_DELAY_JUDGE;
  164.     add_timer(&tpdev->tp_timer);
  165.    
  166.      CLR_INT(TP_INT);
  167.     //we will turn on the irq in the timer_handler
  168.     return IRQ_HANDLED;
  169. }
  170. static int sep4020_tp_open(struct inode *inode, struct file *filp)
  171. {
  172.     if( s_tp_openflag )
  173.          return -EBUSY;
  174.     s_tp_openflag = 1;
  175.     tpdev->zpix = 4;//4 means up
  176.     tpdev->xpix = 0;
  177.     tpdev->ypix = 0;
  178.     s_pen_status  = PEN_UP;
  179.     sep4020_tp_setup();
  180.     return 0;
  181. }
  182. static int sep4020_tp_release(struct inode *inode, struct file *filp)
  183. {
  184.     s_tp_openflag = 0;
  185.     return 0;
  186. }
  187. static ssize_t sep4020_tp_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  188. {
  189.     unsigned short a[3] = {0};
  190.     a[0] = tpdev->zpix;
  191.     a[1] = tpdev->xpix;
  192.     a[2] = tpdev->ypix;    
  193. //printk("*************in the kernel xpix is %d,ypix is %d, zpix is %d************rn",tpdev->xpix,tpdev->ypix,tpdev->zpix);
  194.     copy_to_user(buf, a, sizeof(a));
  195.     return 0;
  196. }
  197. static  struct file_operations sep4020_tp_fops = 
  198. {
  199. .owner = THIS_MODULE,
  200. .read  = sep4020_tp_read,
  201. .open  = sep4020_tp_open,
  202. .release = sep4020_tp_release,
  203. };
  204. static int __init sep4020_tp_init(void)
  205.     int err,result;
  206.     dev_t devno = MKDEV(TP_MAJOR, 0);
  207. #ifdef TP_MAJOR
  208. result = register_chrdev_region(devno, 1, "sep4020_tp");//向系统静态申请设备号
  209. #else 
  210. result = alloc_chrdev_region(&devno, 0, 1, "sep4020_tp");//向系统动态申请设备号
  211. #endif
  212.     if(result < 0)
  213.         return result;
  214.     tpdev = kmalloc(sizeof(struct tp_dev),GFP_KERNEL);
  215.     if (!tpdev)
  216.      {
  217.         result = -ENOMEM;
  218.         unregister_chrdev_region(devno,1);
  219.         return result;
  220.         }
  221.     memset(tpdev,0,sizeof(struct tp_dev));
  222.  tpdev->zpix = 4;//4 means up
  223.     //add a irqhandler
  224.     if(request_irq(INTSRC_EXTINT8,sep4020_tp_irqhandler,SA_INTERRUPT,"sep4020_tp",NULL))
  225.         {
  226.         printk("request tp irq8 failed!n");
  227.         unregister_chrdev_region(devno,1);
  228.         kfree(tpdev);
  229.         return -1;
  230.         }
  231.     //init the tpdev device struct
  232.     cdev_init(&tpdev->cdev, &sep4020_tp_fops);
  233.     tpdev->cdev.owner = THIS_MODULE;
  234.     //just init the timer, not add to the kernel now
  235.     setup_timer(&tpdev->tp_timer,tp_timer_handler,0);
  236.          //向系统注册该字符设备
  237.     err = cdev_add(&tpdev->cdev, devno, 1);
  238.     if(err)
  239.         {
  240.         printk("adding errrn");
  241.         unregister_chrdev_region(devno,1);
  242.         kfree(tpdev);
  243.         free_irq(INTSRC_EXTINT8,NULL);
  244.         return err;
  245.         }  
  246.     return 0;
  247. }
  248. static void __exit sep4020_tp_exit(void)
  249. {
  250. cdev_del(&tpdev->cdev);
  251. kfree(tpdev);
  252. free_irq(INTSRC_EXTINT8,NULL);
  253. unregister_chrdev_region(MKDEV(TP_MAJOR, 0),1);
  254. }
  255. module_init(sep4020_tp_init);
  256. module_exit(sep4020_tp_exit);
  257. MODULE_AUTHOR("Leeming Zhang");
  258. MODULE_LICENSE("GPL");