织梦CMS - 轻松建站从此开始!

罗索

嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之触摸屏驱

罗索客 发布于 2010-06-13 20:32 点击:次 
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如有错误之处,谢请指正。
TAG:

嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提 供方便。如有错误之处,谢请指正。

一、移植环境

  • 主  机:VMWare--Fedora 9
  • 开发板:Mini2440--64MB Nand
  • 编译器:arm-linux-gcc-4.3.2

二、移植步骤

1. 准备驱动源码。因为linux-2.6.30.4内核中没有提供合适的ADC驱动和触摸屏驱动,所以这里就直接用友善提供的驱动
 
s3c24xx-adc.h
  1. #ifndef _S3C2410_ADC_H_ 
  2. #define _S3C2410_ADC_H_ 
  3.  
  4. #define ADC_WRITE(ch, prescale)    ((ch)<<16|(prescale)) 
  5.  
  6. #define ADC_WRITE_GETCH(data)    (((data)>>16)&0x7) 
  7. #define ADC_WRITE_GETPRE(data)    ((data)&0xff) 
  8.  
  9. #endif /* _S3C2410_ADC_H_ */ 

mini2440_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 <asm/io.h> 
  11. #include <asm/irq.h> 
  12. #include <asm/uaccess.h> 
  13. #include <mach/regs-clock.h> 
  14. #include <plat/regs-timer.h> 
  15.      
  16. #include <plat/regs-adc.h> 
  17. #include <mach/regs-gpio.h> 
  18. #include <linux/cdev.h> 
  19. #include <linux/miscdevice.h> 
  20.  
  21. #include "s3c24xx-adc.h" 
  22.  
  23. #undef DEBUG 
  24. //#define DEBUG 
  25.  
  26. #ifdef DEBUG 
  27. #define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);} 
  28. #else 
  29. #define DPRINTK(x...) (void)(0) 
  30. #endif 
  31.  
  32. #define DEVICE_NAME    "adc" 
  33.  
  34. static void __iomem *base_addr; 
  35.  
  36. typedef struct { 
  37.     wait_queue_head_t wait; 
  38.     int channel; 
  39.     int prescale; 
  40. }ADC_DEV; 
  41.  
  42. DECLARE_MUTEX(ADC_LOCK); 
  43. static int OwnADC = 0; 
  44.  
  45. static ADC_DEV adcdev; 
  46. static volatile int ev_adc = 0; 
  47. static int adc_data; 
  48.  
  49. static struct clk    *adc_clock; 
  50.  
  51. #define ADCCON (*(volatile unsigned long *)
  52. (base_addr + S3C2410_ADCCON))//ADC control 
  53.  
  54. #define ADCTSC (*(volatile unsigned long *)
  55. (base_addr + S3C2410_ADCTSC))//ADC touch screen control 
  56.  
  57. #define ADCDLY (*(volatile unsigned long *)
  58. (base_addr + S3C2410_ADCDLY))//ADC start or Interval Delay 
  59.  
  60. #define ADCDAT0 (*(volatile unsigned long *)
  61. (base_addr + S3C2410_ADCDAT0))//ADC conversion data 0 
  62.  
  63. #define ADCDAT1 (*(volatile unsigned long *)
  64. (base_addr + S3C2410_ADCDAT1))//ADC conversion data 1 
  65.  
  66. #define ADCUPDN (*(volatile unsigned long *)
  67. (base_addr + 0x14))//Stylus Up/Down interrupt status 
  68.  
  69. #define PRESCALE_DIS (0 << 14) 
  70. #define PRESCALE_EN (1 << 14) 
  71. #define PRSCVL(x) ((x) << 6) 
  72. #define ADC_INPUT(x) ((x) << 3) 
  73. #define ADC_START (1 << 0) 
  74. #define ADC_ENDCVT (1 << 15) 
  75.  
  76. #define START_ADC_AIN(ch, prescale) \ 
  77.     do{ \ 
  78.         ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ 
  79.         ADCCON |= ADC_START; \ 
  80.     }while(0) 
  81.  
  82. static irqreturn_t adcdone_int_handler(int irq, void *dev_id) 
  83.     if (OwnADC) { 
  84.         adc_data = ADCDAT0 & 0x3ff; 
  85.  
  86.         ev_adc = 1; 
  87.         wake_up_interruptible(&adcdev.wait); 
  88.     } 
  89.  
  90.     return IRQ_HANDLED; 
  91.  
  92. static ssize_t s3c2410_adc_read(struct file *filp,
  93.  char *buffer, size_t count, loff_t *ppos) 
  94.     char str[20]; 
  95.     int value; 
  96.     size_t len; 
  97.     if (down_trylock(&ADC_LOCK) == 0) { 
  98.         OwnADC = 1; 
  99.         START_ADC_AIN(adcdev.channel, adcdev.prescale); 
  100.         wait_event_interruptible(adcdev.wait, ev_adc); 
  101.  
  102.         ev_adc = 0; 
  103.  
  104. DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0); 
  105.  
  106.         value = adc_data; 
  107.         sprintf(str,"%5d", adc_data); 
  108.         copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data)); 
  109.  
  110.         OwnADC = 0; 
  111.         up(&ADC_LOCK); 
  112.     } else { 
  113.         value = -1; 
  114.     } 
  115.  
  116.     len = sprintf(str, "%d\n", value); 
  117.     if (count >= len) { 
  118.         int r = copy_to_user(buffer, str, len); 
  119.         return r ? r : len; 
  120.     } else { 
  121.         return -EINVAL; 
  122.     } 
  123.  
  124. static int s3c2410_adc_open(struct inode *inode, struct file *filp) 
  125.     init_waitqueue_head(&(adcdev.wait)); 
  126.  
  127.     adcdev.channel=0; 
  128.     adcdev.prescale=0xff; 
  129.  
  130.     DPRINTK( "adc opened\n"); 
  131.     return 0; 
  132.  
  133. static int s3c2410_adc_release(struct inode *inode, struct file *filp) 
  134.     DPRINTK( "adc closed\n"); 
  135.     return 0; 
  136.  
  137. static struct file_operations dev_fops = { 
  138.     owner:    THIS_MODULE, 
  139.     open:    s3c2410_adc_open, 
  140.     read:    s3c2410_adc_read,     
  141.     release:    s3c2410_adc_release, 
  142. }; 
  143.  
  144. static struct miscdevice misc = { 
  145.     .minor = MISC_DYNAMIC_MINOR, 
  146.     .name = DEVICE_NAME, 
  147.     .fops = &dev_fops, 
  148. }; 
  149.  
  150. static int __init dev_init(void
  151.     int ret; 
  152.  
  153.     base_addr=ioremap(S3C2410_PA_ADC,0x20); 
  154.     if (base_addr == NULL) { 
  155.         printk(KERN_ERR "Failed to remap register block\n"); 
  156.         return -ENOMEM; 
  157.     } 
  158.  
  159.     adc_clock = clk_get(NULL, "adc"); 
  160.     if (!adc_clock) { 
  161.         printk(KERN_ERR "failed to get adc clock source\n"); 
  162.         return -ENOENT; 
  163.     } 
  164.     clk_enable(adc_clock); 
  165.      
  166.     /* normal ADC */ 
  167.     ADCTSC = 0; 
  168.  
  169. ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); 
  170.     if (ret) { 
  171.         iounmap(base_addr); 
  172.         return ret; 
  173.     } 
  174.  
  175.     ret = misc_register(&misc); 
  176.  
  177.     printk (DEVICE_NAME"\tinitialized\n"); 
  178.     return ret; 
  179.  
  180. static void __exit dev_exit(void
  181.     free_irq(IRQ_ADC, &adcdev); 
  182.     iounmap(base_addr); 
  183.  
  184.     if (adc_clock) { 
  185.         clk_disable(adc_clock); 
  186.         clk_put(adc_clock); 
  187.         adc_clock = NULL; 
  188.     } 
  189.  
  190.     misc_deregister(&misc); 
  191.  
  192. EXPORT_SYMBOL(ADC_LOCK); 
  193. module_init(dev_init); 
  194. module_exit(dev_exit); 
  195. MODULE_LICENSE("GPL"); 
  196. MODULE_AUTHOR("FriendlyARM Inc."); 

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 <asm/io.h> 
  12. #include <asm/irq.h> 
  13.  
  14. #include <plat/regs-adc.h> 
  15. #include <mach/regs-gpio.h> 
  16.  
  17. /* For ts.dev.id.version */ 
  18. #define S3C2410TSVERSION    0x0101 
  19.  
  20. #define WAIT4INT(x) (((x)<<8) | \ 
  21.  S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \ 
  22.  S3C2410_ADCTSC_XY_PST(3)) 
  23.  
  24. #define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | 
  25. S3C2410_ADCTSC_XP_SEN |S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0)) 
  26.  
  27. static char *s3c2410ts_name = "s3c2410 TouchScreen"
  28.  
  29. static    struct input_dev *dev; 
  30. static    long xp; 
  31. static    long yp; 
  32. static    int count; 
  33.  
  34. extern struct semaphore ADC_LOCK; 
  35. static int OwnADC = 0; 
  36.  
  37. static void __iomem *base_addr; 
  38.  
  39. static inline void s3c2410_ts_connect(void
  40.     s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON); 
  41.     s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON); 
  42.     s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON); 
  43.     s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON); 
  44.  
  45. static void touch_timer_fire(unsigned long data) 
  46.       unsigned long data0; 
  47.       unsigned long data1; 
  48.     int updown; 
  49.  
  50.       data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
  51.       data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
  52.  
  53.      updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN))
  54.  && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); 
  55.  
  56.      if (updown) {
  57.          if (count != 0) {
  58.             long tmp;
  59.             tmp = xp;
  60.             xp = yp;
  61.             yp = tmp;
  62.             xp >>= 2;
  63.             yp >>= 2;
  64. #ifdef CONFIG_TOUCHSCREEN_MY2440_DEBUG 
  65. struct timeval tv; 
  66. do_gettimeofday(&tv); 
  67. printk(KERN_DEBUG "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, xp, yp); 
  68. #endif 
  69. input_report_abs(dev, ABS_X, xp); 
  70. input_report_abs(dev, ABS_Y, yp); 
  71. input_report_key(dev, BTN_TOUCH, 1); 
  72. input_report_abs(dev, ABS_PRESSURE, 1); 
  73. input_sync(dev); 
  74.          } 
  75.          xp = 0; 
  76.          yp = 0; 
  77.          count = 0; 
  78.  
  79. iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); 
  80. iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,
  81.  base_addr+S3C2410_ADCCON); 
  82.      } else { 
  83.          count = 0; 
  84.  
  85.          input_report_key(dev, BTN_TOUCH, 0); 
  86.          input_report_abs(dev, ABS_PRESSURE, 0); 
  87.          input_sync(dev); 
  88.  
  89.          iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); 
  90.         if (OwnADC) { 
  91.             OwnADC = 0; 
  92.             up(&ADC_LOCK); 
  93.         } 
  94.      } 
  95.  
  96. static struct timer_list touch_timer = 
  97.         TIMER_INITIALIZER(touch_timer_fire, 0, 0); 
  98.  
  99. static irqreturn_t stylus_updown(int irq, void *dev_id) 
  100.     unsigned long data0; 
  101.     unsigned long data1; 
  102.     int updown; 
  103.  
  104.     if (down_trylock(&ADC_LOCK) == 0) { 
  105.         OwnADC = 1; 
  106.         data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
  107.         data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
  108.  
  109. updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); 
  110.  
  111.         if (updown) { 
  112.             touch_timer_fire(0); 
  113.         } else { 
  114.             OwnADC = 0; 
  115.             up(&ADC_LOCK); 
  116.         } 
  117.     } 
  118.  
  119.     return IRQ_HANDLED; 
  120.  
  121. static irqreturn_t stylus_action(int irq, void *dev_id) 
  122.     unsigned long data0; 
  123.     unsigned long data1; 
  124.  
  125.     if (OwnADC) { 
  126.         data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
  127.         data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
  128.  
  129.         xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK; 
  130.         yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK; 
  131.         count++; 
  132.  
  133.      if (count < (1<<2)) { 
  134. iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); 
  135. iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,
  136.  base_addr+S3C2410_ADCCON); 
  137.         } else { 
  138.             mod_timer(&touch_timer, jiffies+1); 
  139.             iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC); 
  140.         } 
  141.     } 
  142.  
  143.     return IRQ_HANDLED; 
  144.  
  145. static struct clk    *adc_clock; 
  146.  
  147. static int __init s3c2410ts_init(void
  148.     struct input_dev *input_dev; 
  149.  
  150.     adc_clock = clk_get(NULL, "adc"); 
  151.     if (!adc_clock) { 
  152.         printk(KERN_ERR "failed to get adc clock source\n"); 
  153.         return -ENOENT; 
  154.     } 
  155.     clk_enable(adc_clock); 
  156.  
  157.     base_addr=ioremap(S3C2410_PA_ADC,0x20); 
  158.     if (base_addr == NULL) { 
  159.         printk(KERN_ERR "Failed to remap register block\n"); 
  160.         return -ENOMEM; 
  161.     } 
  162.  
  163.     /* Configure GPIOs */ 
  164.     s3c2410_ts_connect(); 
  165.  
  166.     iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\ 
  167.          base_addr+S3C2410_ADCCON); 
  168.     iowrite32(0xffff, base_addr+S3C2410_ADCDLY); 
  169.     iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); 
  170.  
  171.     /* Initialise input stuff */ 
  172.     input_dev = input_allocate_device(); 
  173.  
  174.     if (!input_dev) { 
  175.         printk(KERN_ERR "Unable to allocate the input device !!\n"); 
  176.         return -ENOMEM; 
  177.     } 
  178.  
  179.     dev = input_dev; 
  180.     dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 
  181.     dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH); 
  182.     input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0); 
  183.     input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0); 
  184.     input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0); 
  185.  
  186.     dev->name = s3c2410ts_name; 
  187.     dev->id.bustype = BUS_RS232; 
  188.     dev->id.vendor = 0xDEAD; 
  189.     dev->id.product = 0xBEEF; 
  190.     dev->id.version = S3C2410TSVERSION; 
  191.  
  192.     /* Get irqs */ 
  193.     if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, 
  194.         "s3c2410_action", dev)) { 
  195.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n"); 
  196.         iounmap(base_addr); 
  197.         return -EIO; 
  198.     } 
  199.     if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, 
  200.             "s3c2410_action", dev)) { 
  201.         printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n"); 
  202.         iounmap(base_addr); 
  203.         return -EIO; 
  204.     } 
  205.  
  206.     printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name); 
  207.  
  208.     /* All went ok, so register to the input system */ 
  209.     input_register_device(dev); 
  210.  
  211.     return 0; 
  212.  
  213. static void __exit s3c2410ts_exit(void
  214.     disable_irq(IRQ_ADC); 
  215.     disable_irq(IRQ_TC); 
  216.     free_irq(IRQ_TC,dev); 
  217.     free_irq(IRQ_ADC,dev); 
  218.  
  219.     if (adc_clock) { 
  220.         clk_disable(adc_clock); 
  221.         clk_put(adc_clock); 
  222.         adc_clock = NULL; 
  223.     } 
  224.  
  225.     input_unregister_device(dev); 
  226.     iounmap(base_addr); 
  227.  
  228. module_init(s3c2410ts_init); 
  229. module_exit(s3c2410ts_exit); 

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


 

#cp -f s3c24xx-adc.h mini2440_adc.c /linux-2.6.30.4/drivers/char/

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


 

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

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

config MY2440_ADC
    bool "ADC device for my2440"
    default y


 

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

obj-$(CONFIG_MY2440_ADC)  += mini2440_adc.o

#gedit linux-2.6.30.4/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 linux-2.6.30.4/drivers/input/touchscreen/Makefile  //添加如下内容

obj-$(CONFIG_TOUCHSCREEN_MY2440) += s3c2410_ts.o

4. 修改内核配置选项
 

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)


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

6. 创建触摸屏设备节点并测试。由启动信息得知触摸屏设备为输入类设备,如下图操作可以得知输入类设备的主设备号为13,又查看总线的具体输入设备可得知该设 备的详细信息,根据这些信息我们建立好设备节点,设置内核调试级别为8,然后打开触摸屏设备,点击触摸屏,此时可以看到打印的坐标信息,即触摸屏可正常使 用了

(hbhuanggang)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201006/9649.html]
本文出处:blog.chinaunix.net 作者:hbhuanggang
顶一下
(3)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容