Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3066
  • 博文数量: 3
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-04 11:33
文章分类
文章存档

2013年(3)

我的朋友
最近访客

分类: 嵌入式

2013-09-04 11:34:12

原文地址:触摸屏驱动移植 作者:FreedomXura

一.触摸屏驱动:有3个文件:s3c2410_ts.c, s3c2440_adc.c, s3c2440adc.h ,参考友善之臂。

1.s3c2410_ts.c

  1. #include <linux/errno.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/slab.h>
  5. #include <linux/input.h>
  6. #include <linux/init.h>
  7. #include <linux/serio.h>
  8. #include <linux/delay.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/clk.h>
  11. #include <linux/gpio.h>
  12. #include <asm/io.h>
  13. #include <asm/irq.h>

  14. #include <plat/regs-adc.h>
  15. #include <mach/regs-gpio.h>

  16. /* For ts.dev.id.version */
  17. #define S3C2410TSVERSION    0x0101

  18. #define WAIT4INT(x) (((x)<<8) | \
  19.          S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
  20.          S3C2410_ADCTSC_XY_PST(3))

  21. #define AUTOPST     (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
  22.          S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))

  23. static char *s3c2410ts_name = "s3c2410 TouchScreen";

  24. static    struct input_dev *dev;
  25. static    long xp;
  26. static    long yp;
  27. static    int count;

  28. extern struct semaphore ADC_LOCK;
  29. static int OwnADC = 0;

  30. static void __iomem *base_addr;

  31. static inline void s3c2410_ts_connect(void)
  32. {
  33.     s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
  34.     s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
  35.     s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
  36.     s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
  37. }

  38. static void touch_timer_fire(unsigned long data)
  39. {
  40.       unsigned long data0;
  41.       unsigned long data1;
  42.     int updown;

  43.       data0 = ioread32(base_addr+S3C2410_ADCDAT0);
  44.       data1 = ioread32(base_addr+S3C2410_ADCDAT1);

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

  46.      if (updown) {
  47.          if (count != 0) {
  48.             long tmp;
  49.                                                                                                  
  50.             tmp = xp;
  51.             xp = yp;
  52.             yp = tmp;
  53.                                                                                                  
  54.                         xp >>= 2;
  55.                         yp >>= 2;

  56.              input_report_abs(dev, ABS_X, xp);
  57.              input_report_abs(dev, ABS_Y, yp);

  58.              input_report_key(dev, BTN_TOUCH, 1);
  59.              input_report_abs(dev, ABS_PRESSURE, 1);
  60.              input_sync(dev);
  61.          }

  62.          xp = 0;
  63.          yp = 0;
  64.          count = 0;

  65.          iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
  66.          iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
  67.      } else {
  68.          count = 0;

  69.          input_report_key(dev, BTN_TOUCH, 0);
  70.          input_report_abs(dev, ABS_PRESSURE, 0);
  71.          input_sync(dev);

  72.          iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
  73.         if (OwnADC) {
  74.             OwnADC = 0;
  75.             up(&ADC_LOCK);
  76.         }
  77.      }
  78. }

  79. static struct timer_list touch_timer =
  80.         TIMER_INITIALIZER(touch_timer_fire, 0, 0);

  81. static irqreturn_t stylus_updown(int irq, void *dev_id)
  82. {
  83.     unsigned long data0;
  84.     unsigned long data1;
  85.     int updown;

  86.     if (down_trylock(&ADC_LOCK) == 0) {
  87.         OwnADC = 1;
  88.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);
  89.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);

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

  91.         if (updown) {
  92.             touch_timer_fire(0);
  93.         } else {
  94.             OwnADC = 0;
  95.             up(&ADC_LOCK);
  96.         }
  97.     }

  98.     return IRQ_HANDLED;
  99. }


  100. static irqreturn_t stylus_action(int irq, void *dev_id)
  101. {
  102.     unsigned long data0;
  103.     unsigned long data1;

  104.     if (OwnADC) {
  105.         data0 = ioread32(base_addr+S3C2410_ADCDAT0);
  106.         data1 = ioread32(base_addr+S3C2410_ADCDAT1);

  107.         xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
  108.         yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
  109.         count++;

  110.      if (count < (1<<2)) {
  111.             iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
  112.             iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
  113.         } else {
  114.             mod_timer(&touch_timer, jiffies+1);
  115.             iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
  116.         }
  117.     }

  118.     return IRQ_HANDLED;
  119. }

  120. static struct clk    *adc_clock;

  121. static int __init s3c2410ts_init(void)
  122. {
  123.     struct input_dev *input_dev;

  124.     adc_clock = clk_get(NULL, "adc");
  125.     if (!adc_clock) {
  126.         printk(KERN_ERR "failed to get adc clock source\n");
  127.         return -ENOENT;
  128.     }
  129.     clk_enable(adc_clock);

  130.     base_addr=ioremap(S3C2410_PA_ADC,0x20);
  131.     if (base_addr == NULL) {
  132.         printk(KERN_ERR "Failed to remap register block\n");
  133.         return -ENOMEM;
  134.     }

  135.     /* Configure GPIOs */
  136.     s3c2410_ts_connect();

  137.     iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\
  138.          base_addr+S3C2410_ADCCON);
  139.     iowrite32(0xffff, base_addr+S3C2410_ADCDLY);
  140.     iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);

  141.     /* Initialise input stuff */
  142.     input_dev = input_allocate_device();

  143.     if (!input_dev) {
  144.         printk(KERN_ERR "Unable to allocate the input device !!\n");
  145.         return -ENOMEM;
  146.     }

  147.     dev = input_dev;
  148.     dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
  149.     dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
  150.     input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
  151.     input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
  152.     input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);

  153.     dev->name = s3c2410ts_name;
  154.     dev->id.bustype = BUS_RS232;
  155.     dev->id.vendor = 0xDEAD;
  156.     dev->id.product = 0xBEEF;
  157.     dev->id.version = S3C2410TSVERSION;


  158.     /* Get irqs */
  159.     if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
  160.         "s3c2410_action", dev)) {
  161.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
  162.         iounmap(base_addr);
  163.         return -EIO;
  164.     }
  165.     if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
  166.             "s3c2410_action", dev)) {
  167.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
  168.         iounmap(base_addr);
  169.         return -EIO;
  170.     }

  171.     printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);

  172.     /* All went ok, so register to the input system */
  173.     input_register_device(dev);

  174.     return 0;
  175. }

  176. static void __exit s3c2410ts_exit(void)
  177. {
  178.     disable_irq(IRQ_ADC);
  179.     disable_irq(IRQ_TC);
  180.     free_irq(IRQ_TC,dev);
  181.     free_irq(IRQ_ADC,dev);

  182.     if (adc_clock) {
  183.         clk_disable(adc_clock);
  184.         clk_put(adc_clock);
  185.         adc_clock = NULL;
  186.     }

  187.     input_unregister_device(dev);
  188.     iounmap(base_addr);
  189. }


  190. module_init(s3c2410ts_init);
  191. module_exit(s3c2410ts_exit);

2.s3c2440_adc.h

  1. #ifndef _S3C2410_ADC_H_
  2. #define _S3C2410_ADC_H_

  3. #define ADC_WRITE(ch, prescale)    ((ch)<<16|(prescale))

  4. #define ADC_WRITE_GETCH(data)    (((data)>>16)&0x7)
  5. #define ADC_WRITE_GETPRE(data)    ((data)&0xff)

  6. #endif /* _S3C2410_ADC_H_ */

3.s3c2440_adc.c

 

  1. #include <linux/errno.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/slab.h>
  5. #include <linux/input.h>
  6. #include <linux/init.h>
  7. #include <linux/serio.h>
  8. #include <linux/delay.h>
  9. #include <linux/clk.h>
  10. #include <linux/wait.h>
  11. #include <linux/sched.h>
  12. #include <asm/io.h>
  13. #include <asm/irq.h>
  14. #include <asm/uaccess.h>
  15. #include <mach/regs-clock.h>
  16. #include <plat/regs-timer.h>
  17.     
  18. #include <plat/regs-adc.h>
  19. #include <mach/regs-gpio.h>
  20. #include <linux/cdev.h>
  21. #include <linux/miscdevice.h>

  22. #include "s3c2440_adc.h"

  23. #undef DEBUG
  24. //#define DEBUG
  25. #ifdef DEBUG
  26. #define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
  27. #else
  28. #define DPRINTK(x...) (void)(0)
  29. #endif

  30. #define DEVICE_NAME    "adc"

  31. static void __iomem *base_addr;

  32. typedef struct {
  33.     wait_queue_head_t wait;
  34.     int channel;
  35.     int prescale;
  36. }ADC_DEV;

  37. DECLARE_MUTEX(ADC_LOCK);
  38. static int OwnADC = 0;

  39. static ADC_DEV adcdev;
  40. static volatile int ev_adc = 0;
  41. static int adc_data;

  42. static struct clk    *adc_clock;

  43. #define ADCCON (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))    //ADC control
  44. #define ADCTSC (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))    //ADC touch screen control
  45. #define ADCDLY (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))    //ADC start or Interval Delay
  46. #define ADCDAT0 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0))    //ADC conversion data 0
  47. #define ADCDAT1 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1))    //ADC conversion data 1
  48. #define ADCUPDN (*(volatile unsigned long *)(base_addr + 0x14))    //Stylus Up/Down interrupt status

  49. #define PRESCALE_DIS (0 << 14)
  50. #define PRESCALE_EN (1 << 14)
  51. #define PRSCVL(x) ((x) << 6)
  52. #define ADC_INPUT(x) ((x) << 3)
  53. #define ADC_START (1 << 0)
  54. #define ADC_ENDCVT (1 << 15)

  55. #define START_ADC_AIN(ch, prescale) \
  56.     do{ \
  57.         ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
  58.         ADCCON |= ADC_START; \
  59.     }while(0)


  60. static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
  61. {
  62.     if (OwnADC) {
  63.         adc_data = ADCDAT0 & 0x3ff;

  64.         ev_adc = 1;
  65.         wake_up_interruptible(&adcdev.wait);
  66.     }

  67.     return IRQ_HANDLED;
  68. }

  69. static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
  70. {
  71.     char str[20];
  72.     int value;
  73.     size_t len;
  74.     if (down_trylock(&ADC_LOCK) == 0) {
  75.         OwnADC = 1;
  76.         START_ADC_AIN(adcdev.channel, adcdev.prescale);
  77.         wait_event_interruptible(adcdev.wait, ev_adc);

  78.         ev_adc = 0;

  79.         DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);

  80.         value = adc_data;

  81.         OwnADC = 0;
  82.         up(&ADC_LOCK);
  83.     } else {
  84.         value = -1;
  85.     }

  86.     len = sprintf(str, "%d\n", value);
  87.     if (count >= len) {
  88.         int r = copy_to_user(buffer, str, len);
  89.         return r ? r : len;
  90.     } else {
  91.         return -EINVAL;
  92.     }
  93. }

  94. static int s3c2410_adc_open(struct inode *inode, struct file *filp)
  95. {
  96.     init_waitqueue_head(&(adcdev.wait));

  97.     adcdev.channel=0;
  98.     adcdev.prescale=0xff;

  99.     DPRINTK( "adc opened\n");
  100.     return 0;
  101. }

  102. static int s3c2410_adc_release(struct inode *inode, struct file *filp)
  103. {
  104.     DPRINTK( "adc closed\n");
  105.     return 0;
  106. }


  107. static struct file_operations dev_fops = {
  108.     owner:    THIS_MODULE,
  109.     open:    s3c2410_adc_open,
  110.     read:    s3c2410_adc_read,    
  111.     release:    s3c2410_adc_release,
  112. };

  113. static struct miscdevice misc = {
  114.     .minor = MISC_DYNAMIC_MINOR,
  115.     .name = DEVICE_NAME,
  116.     .fops = &dev_fops,
  117. };

  118. static int __init dev_init(void)
  119. {
  120.     int ret;

  121.     base_addr=ioremap(S3C2410_PA_ADC,0x20);
  122.     if (base_addr == NULL) {
  123.         printk(KERN_ERR "Failed to remap register block\n");
  124.         return -ENOMEM;
  125.     }

  126.     adc_clock = clk_get(NULL, "adc");
  127.     if (!adc_clock) {
  128.         printk(KERN_ERR "failed to get adc clock source\n");
  129.         return -ENOENT;
  130.     }
  131.     clk_enable(adc_clock);
  132.     
  133.     /* normal ADC */
  134.     ADCTSC = 0;

  135.     ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
  136.     if (ret) {
  137.         iounmap(base_addr);
  138.         return ret;
  139.     }

  140.     ret = misc_register(&misc);

  141.     printk (DEVICE_NAME"\tinitialized\n");
  142.     return ret;
  143. }

  144. static void __exit dev_exit(void)
  145. {
  146.     free_irq(IRQ_ADC, &adcdev);
  147.     iounmap(base_addr);

  148.     if (adc_clock) {
  149.         clk_disable(adc_clock);
  150.         clk_put(adc_clock);
  151.         adc_clock = NULL;
  152.     }

  153.     misc_deregister(&misc);
  154. }

  155. EXPORT_SYMBOL(ADC_LOCK);
  156. module_init(dev_init);
  157. module_exit(dev_exit);
  158. MODULE_LICENSE("GPL");
  159. MODULE_AUTHOR("FriendlyARM Inc.");

. 部署驱动源代码到内核中

#cp -f s3c2440_adc.h s3c2440_adc.c linux-2.6.31/drivers/char/

#cp -f s3c2410_ts.c linux-2.6.31/drivers/input/touchscreen/


三. 将驱动模块添加到内核配置文件中
 

#gedit linux-2.6.30.4/drivers/char/Kconfig  //添加如下内容

config MY2440_ADC
    bool "ADC device for my2440"
    default y


#gedit drivers/char/Makefile  //添加如下内容

obj-$(CONFIG_MY2440_ADC)  += s3c2440_adc.o

#gedit drivers/input/touchscreen/Kconfig  //添加如下内容

config TOUCHSCREEN_MY2440
    tristate "MY2440 touchscreens input driver"
    default y
 
config TOUCHSCREEN_MY2440_DEBUG
    boolean "MY2440 touchscreens input driver debug messages"
    depends on TOUCHSCREEN_MY2440
    help
        Select this if you want debug messages

#gedit drivers/input/touchscreen/Makefile  //添加如下内容

obj-$(CONFIG_TOUCHSCREEN_MY2440) += s3c2410_ts.o

四. 修改内核配置选项
 

Device Drivers --->
    Input device support --->
        (240) Horizontal screen resolution 
        (320) Vertical screen resolution 
        [*] Touchscreens ---> 
            <*> MY2440 touchscreens input driver (NEW)
            [*] MY2440 touchscreens input driver debug messages 
    Character devices ---> 
        [*] ADC device for my2440 (NEW)


五. 编译内核并下载到开发板上,从启动信息可以看到触摸屏驱动加载成功

s3c2410 TouchScreen successfully loaded
input: s3c2410 TouchScreen as /class/input/input0


#cat /proc/devices   可以查看到input设备

得知输入类设备的主设备号为13,又查看总线的具体输入设备可得知该设备的详细信息,根据这些信息我们建立好设备节点,设置内核调试级别为8,然后打开触摸屏设备.

#mkdir /dev/input
#mknod /dev/input/event0 c 13 64

#echo 8 > /proc/sys/kernel/printk

#cat /dev/input/event0

点击触摸屏,此时可以看到打印的坐标信息,即触摸屏可正常使用了.

阅读(117) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~