Chinaunix首页 | 论坛 | 博客
  • 博客访问: 854290
  • 博文数量: 286
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1980
  • 用 户 组: 普通用户
  • 注册时间: 2014-05-04 16:41
文章分类

全部博文(286)

文章存档

2020年(2)

2018年(5)

2017年(95)

2016年(69)

2015年(15)

2014年(100)

我的朋友

分类: 嵌入式

2014-09-15 22:30:42

 Linux移植开发指南学习笔记(十)1  添加触摸屏驱动 (Fedora9)

1、在内核中添加触摸屏驱动程序 
    Linux-2.6.32.2 内核也没有包含支持S3C2440 的触摸屏驱动,因此我们自行设计了一个s3c2410_ts.c,它位于linux-src/drivers/input/touchscreen 目录下,你可以自己增加一个s3c2410_ts.c 文件,并复制如下内容: 
 #include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include  
#include  
 
/* For ts.dev.id.version */ 
#define S3C2410TSVERSION  0x0101 
 
#define WAIT4INT(x)  (((x)<<8) | \ 
              S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
         S3C2410_ADCTSC_XY_PST(3)) 
 
#define AUTOPST      (S3C2410_ADCTSC_YM_SEN  |  S3C2410_ADCTSC_YP_SEN  | 
S3C2410_ADCTSC_XP_SEN | \ 
         S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0)) 
 
static char *s3c2410ts_name = "s3c2410 TouchScreen"; 
 
static  struct input_dev *dev; 
static long xp; 
static long yp; 
static int count; 
 
extern struct semaphore ADC_LOCK; 
static int OwnADC = 0; 
 
 
static void __iomem *base_addr; 
 
static inline void s3c2410_ts_connect(void) 

 s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON); 
 s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON); 
 s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON); 
 s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON); 
}

static void touch_timer_fire(unsigned long data) 

    unsigned long data0; 
    unsigned long data1; 
 int updown; 
 
    data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
    data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
 
    updown = (!(data0 & S3C2410_ADCDAT0_UPDOW N)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
 
    if (updown) { 
      if (count != 0) { 
   long tmp; 
                                                                                              
   tmp = xp; 
   xp = yp; 
   yp = tmp; 
                                                                                              
                        xp >>= 2; 
                        yp >>= 2; 
 
    input_report_abs(dev, ABS_X, xp); 
    input_report_abs(dev, ABS_Y, yp); 
 
    input_report_key(dev, BTN_TOUCH, 1); 
    input_report_abs(dev, ABS_PRESSURE, 1); 
    input_sync(dev); 
     } 
 
     xp = 0; 
      yp = 0; 
      count = 0; 
 
      iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); 
   iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, 
base_addr+S3C2410_ADCCON); 
    } else { 
      count = 0; 
input_report_key(dev, BTN_TOUCH, 0); 
     input_report_abs(dev, ABS_PRESSURE, 0); 
     input_sync(dev); 
 
     iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); 
  if (OwnADC) { 
   OwnADC = 0; 
   up(&ADC_LOCK); 
  } 
   } 

 
static struct timer_list touch_timer = 
  TIMER_INITIALIZER(touch_timer_fire, 0, 0); 
 
static irqreturn_t stylus_updown(int irq, void *dev_id) 

 unsigned long data0; 
 unsigned long data1; 
 int updown; 
 
  if (down_trylock(&ADC_LOCK) == 0) { 
  OwnADC = 1; 
  data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
  data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
 
  updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & 
S3C2410_ADCDAT0_UPDOWN)); 
 
  if (updown) { 
   touch_timer_fire(0); 
  } else { 
   OwnADC = 0; 
   up(&ADC_LOCK); 
  } 
 } 
 
 return IRQ_HANDLED;

 
 
static irqreturn_t stylus_action(int irq, void *dev_id) 

 unsigned long data0; 
 unsigned long data1; 
 
 if (OwnADC) { 
  data0 = ioread32(base_addr+S3C2410_ADCDAT0); 
  data1 = ioread32(base_addr+S3C2410_ADCDAT1); 
 
  xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK; 
    yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK; 
  count++; 
 
      if (count < (1<<2)) { 
   iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE  |  AUTOPST, 
base_addr+S3C2410_ADCTSC); 
   iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, 
base_addr+S3C2410_ADCCON); 
  } else { 
   mod_timer(&touch_timer, jiffies+1); 
   iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC); 
  } 
 } 
 
 return IRQ_HANDLED; 

 
static struct clk  *adc_clock; 
 
static int __init s3c2410ts_init(void) 

  struct input_dev *input_dev; 
 
  adc_clock = clk_get(NULL, "adc"); 
  if (!adc_clock) { 
    printk(KERN_ERR "failed to get adc clock source\n"); 
return -ENOENT; 
 } 
 clk_enable(adc_clock); 
 
 base_addr=ioremap(S3C2410_PA_ADC,0x20); 
  if (base_addr == NULL) { 
    printk(KERN_ERR "Failed to remap register block\n"); 
  return -ENOMEM; 
 } 
 
  /* Configure GPIOs */ 
 s3c2410_ts_connect(); 
 
  iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\ 
         base_addr+S3C2410_ADCCON); 
  iowrite32(0xffff,  base_addr+S3C2410_ADCDLY); 
 iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); 
 
  /* Initialise input stuff */ 
 input_dev = input_allocate_device(); 
 
  if (!input_dev) { 
    printk(KERN_ERR "Unable to allocate the input device !!\n"); 
  return -ENOMEM; 
 } 
 
 dev = input_dev; 
 dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) |  BIT(EV_ABS); 
  dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH); 
  input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0); 
  input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0); 
  input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0); 
 
  dev->name = s3c2410ts_name; 
  dev->id.bustype = BUS_RS232; 
  dev->id.vendor = 0xDEAD; 
  dev->id.product = 0xBEEF; 
  dev->id.version = S3C2410TSVERSION; 

/* Get irqs */ 
  if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, 
  "s3c2410_action", dev)) { 
    printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n"); 
  iounmap(base_addr); 
  return -EIO; 
 } 
  if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, 
   "s3c2410_action", dev)) { 
    printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n"); 
  iounmap(base_addr); 
  return -EIO; 
 } 
 
  printk(KERN_INFO "%s successfully  loaded\n", s3c2410ts_name); 
 
  /* All went ok, so register to the input system */ 
 input_register_device(dev); 
 
 return 0; 

 
static void __exit s3c2410ts_exit(void) 

 disable_irq(IRQ_ADC); 
 disable_irq(IRQ_TC); 
 free_irq(IRQ_TC,dev); 
 free_irq(IRQ_ADC,dev); 
 
 if (adc_clock) { 
  clk_disable(adc_clock); 
  clk_put(adc_clock); 
  adc_clock = NULL; 
 } 
 
 input_unregister_device(dev); 
 iounmap(base_addr); 


module_init(s3c2410ts_init); 
module_exit(s3c2410ts_exit); 


然后在linux-2.6.32.2/drivers/input/touchscreen/Makefile 文件中添加该源代码的目标模块,如图红色部分:
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)       += zylonite-wm97xx.o 
obj-$(CONFIG_TOUCHSCREEN_W90X900)       += w90p910_ts.o 
obj-$(CONFIG_TOUCHSCREEN_PCAP)          += pcap_ts.o 
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o   (第一次写错了,结果驱动没工作


再打开linux-2.6.32.2/drivers/input/touchscreen/Kconfig 文件,加入如下红色部分,这样就在内核配置中添加了mini2440 的触摸屏驱动选项:
menuconfig INPUT_TOUCHSCREEN 
        bool "Touchscreens" 
        help 
          Say Y here, and a list of supported touchscreens will be displayed. 
          This option doesn't affect the kernel. 
 
          If unsure, say Y. 
 
if INPUT_TOUCHSCREEN 
 
config TOUCHSCREEN_S3C2410 
        tristate "Samsung S3C2410 touchscreen input driver" 
                depends on MACH_MINI2440 && INPUT && INPUT_TOUCHSCREEN && MINI2440_ADC 
        help 
          Say Y here if you have the s3c2410 touchscreen. 
 
          If unsure, say N. 
 
                    To compile this driver as a module, choose M here: the 
          module will be called s3c2410_ts. 
 
config TOUCHSCREEN_ADS7846 
        tristate "ADS7846/TSC2046 and ADS7843 based touchscreens" 
        depends on SPI_MASTER 
        depends on HWMON = n || HWMON 
        help
至此,我们就已经在内核中添加完了触摸屏驱动。

2 、配置编译内核并测试触摸屏驱动 
    在命令行执行:make menuconfig ,然后依次选择如下子菜单,找到刚刚添加的触摸屏驱动选项: 
Device Drivers  ---> 
    Input device support  --->   
[*]   Touchscreens  --->  
如图所示,按空格键选中触摸屏驱动配置选项
退出并保存以上内核配置,在命令行输入:make zImage,将生成arch/arm/boot/zImage文件,使用 supervivi 的“k”命令把它烧写到开发板。

在此我们还是使用缺省的文件系统 root_qtopia,可以看到屏幕上出现校正界面: 依照屏幕提示,使用触摸笔逐步点击“十”型交叉点,即可进入 qtopia 系统,通过触摸屏操作。
阅读(1210) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~