Chinaunix首页 | 论坛 | 博客
  • 博客访问: 968507
  • 博文数量: 214
  • 博客积分: 10173
  • 博客等级: 上将
  • 技术积分: 1867
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-18 13:48
文章分类

全部博文(214)

文章存档

2012年(1)

2010年(13)

2009年(5)

2008年(98)

2007年(97)

分类: LINUX

2007-12-06 21:30:44

  本移植是先从 Ben Dooks 的网站上下载了部分代码,同时在网下载了一个2410的
 touch screen 驱动程序,做了简单修改完成的.这个简单的触摸屏驱动程序还不是
 很完善,还需要改进.
 
简单触摸屏驱动移植过程如下:


一. 如果你的kernel里面没有 reg-adc.h 则需要到 Ben Dooks 的网站下载相关补丁
    文件位置在 include/asm-arm/arch-s3c2410/regs-adc.h, 并在其添加如下内容

#define S3C2410_ADCTSC_XY_PST_N     (0x0<<0)
#define S3C2410_ADCTSC_XY_PST_X     (0x1<<0)
#define S3C2410_ADCTSC_XY_PST_Y  (0x2<<0)
#define S3C2410_ADCTSC_XY_PST_W   (0x3<<0)

二.将下载的2410的驱动程序代码复制到 drivers/input/touchscreen/ 下名为
    s3c2440_ts.c .
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include
//#include
#include
#include

/* For ts.dev.id.version */
#define S3C2440TSVERSION 0x0101

#define WAIT4INT(x)  (((x)<<8) | \
       S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
       S3C2410_ADCTSC_XY_PST_W)

#define AUTOPST      (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
       S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST_N)

#define DEBUG_LVL    KERN_INFO

#ifdef CONFIG_TOUCHSCREEN_S3C2440_DEBUG
#define DBG(x...)       printk(KERN_INFO x)
#else
#define DBG(x...)       do { } while (0)
#endif

/*
 * Definitions & global arrays.
 */


static char *s3c2440ts_name = "s3c2440 TouchScreen";

/*
 * Per-touchscreen data.
 */

struct s3c2440ts {
 struct input_dev *dev;
 long xp;
 long yp;
 int count;
 int shift;
 char phys[32];
};

static struct s3c2440ts ts;
static void __iomem *base_addr;

static void touch_timer_fire(unsigned long data)
{
   unsigned long data0;
   unsigned long data1;
 int updown;

   data0 = readl(base_addr+S3C2410_ADCDAT0);
   data1 = readl(base_addr+S3C2410_ADCDAT1);

  updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
 
 DBG(" data0 = %x, data1 = %x updown = %d  %s : %s : line = %d\n", data0, data1, updown,
   __FUNCTION__, __FILE__, __LINE__);

  if (updown) {
   if (ts.count != 0) {
    ts.xp >>= ts.shift;
    ts.yp >>= ts.shift;
 
#ifdef CONFIG_TOUCHSCREEN_S3C2440_DEBUG
    {
     struct timeval tv;
     do_gettimeofday(&tv);
     printk(DEBUG_LVL "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts.xp, ts.yp);
    }
#endif
   
    input_report_abs(ts.dev, ABS_X, ts.xp);
    input_report_abs(ts.dev, ABS_Y, ts.yp);
 
    input_report_key(ts.dev, BTN_TOUCH, 1);
    input_report_abs(ts.dev, ABS_PRESSURE, 1);
    input_sync(ts.dev);
   }
  
   ts.xp = 0;
   ts.yp = 0;
   ts.count = 0;
 
   writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
   writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
  } else {
   ts.count = 0;
  
   input_report_key(ts.dev, BTN_TOUCH, 0);
   input_report_abs(ts.dev, ABS_PRESSURE, 0);
   input_sync(ts.dev);
  
   writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
  }
}

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

static irqreturn_t stylus_updown(int irq, void *dev_id, struct pt_regs *regs)
{
 unsigned long data0;
 unsigned long data1;
 int updown;

 data0 = readl(base_addr+S3C2410_ADCDAT0);
 data1 = readl(base_addr+S3C2410_ADCDAT1);

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

 DBG("\n data0 = %x, data1 = %x updown = %d  %s : %s : line = %d\n", data0, data1, updown,
   __FUNCTION__, __FILE__, __LINE__);

 /* TODO we should never get an interrupt with updown set while
  * the timer is running, but maybe we ought to verify that the
  * timer isn't running anyways. */
 
 if (updown)
  touch_timer_fire(0);

 return IRQ_HANDLED;
}


static irqreturn_t stylus_action(int irq, void *dev_id, struct pt_regs *regs)
{
 unsigned long data0;
 unsigned long data1;
 
 data0 = readl(base_addr+S3C2410_ADCDAT0);
 data1 = readl(base_addr+S3C2410_ADCDAT1);

 ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
 ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
 ts.count++;

    if (ts.count < (1<< ts.shift)) {
  writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
  writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
 } else {

  DBG(" data0 = %x, data1 = %x, %s : %s : line = %d\n", data0, data1, __FUNCTION__, __FILE__, __LINE__);
  mod_timer(&touch_timer, jiffies+1);
  writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
 }

 return IRQ_HANDLED;
}

static struct clk *adc_clock;

/*
 * The functions for inserting/removing us as a module.
 */

static int __init s3c2440ts_probe(struct device *dev)
{
 struct s3c2440_ts_mach_info *info;
 
 info = ( struct s3c2440_ts_mach_info *)dev->platform_data;

 if (!info)
 {
  printk(KERN_ERR "Hm... too bad : no platform data for ts\n");
  return -EINVAL;
 }
 
#ifdef CONFIG_TOUCHSCREEN_S3C2440_DEBUG
 printk(DEBUG_LVL "Entering s3c2440ts_init\n");
#endif

 memset(&ts, 0, sizeof(struct s3c2440ts));
 ts.dev = input_allocate_device();
 if (!ts.dev)
 {
  printk(KERN_ERR "%s:%s allocate_device\n", __FUNCTION__, __FILE__);
  return -ENOMEM;
 }

 adc_clock = clk_get(NULL, "adc");
 if (!adc_clock) {
  printk(KERN_ERR "failed to get adc clock source\n");
  return -ENOENT;
 }
 //clk_use(adc_clock);
 clk_enable(adc_clock);

#ifdef CONFIG_TOUCHSCREEN_S3C2440_DEBUG
 printk(DEBUG_LVL "got and enabled clock\n");
#endif

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

 if ((info->presc&0xff) > 0)
  writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF), base_addr + S3C2410_ADCCON);
 else
  writel(0,base_addr + S3C2410_ADCCON);


 /* Initialise registers */
 if ((info->delay&0xffff) > 0)
  writel(info->delay & 0xffff,  base_addr + S3C2410_ADCDLY);
 
 writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
 
 /* Initialise input stuff */
 //memset(&ts, 0, sizeof(struct s3c2440ts));
 //init_input_dev(&ts.dev);

 ts.dev->evbit[0] = ts.dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
 ts.dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
 input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
 input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
 input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);

 sprintf(ts.phys, "ts0");

 ts.dev->private = &ts;
 ts.dev->name = s3c2440ts_name;
 ts.dev->phys = ts.phys;
 ts.dev->id.bustype = BUS_RS232;
 ts.dev->id.vendor = 0xDEAD;
 ts.dev->id.product = 0xBEEF;
 ts.dev->id.version = S3C2440TSVERSION;

 ts.shift = info->oversampling_shift;

 /* Get irqs */
 if (request_irq(IRQ_ADC, stylus_action, SA_SAMPLE_RANDOM, "s3c2440_action", ts.dev)) {
  printk(KERN_ERR "s3c2440_ts.c: Could not allocate ts IRQ_ADC !\n");
  iounmap(base_addr);
  return -EIO;
 }
 if (request_irq(IRQ_TC, stylus_updown, SA_SAMPLE_RANDOM, "s3c2440_updown", ts.dev)) {
  printk(KERN_ERR "s3c2440_ts.c: Could not allocate ts IRQ_TC !\n");
  disable_irq(IRQ_ADC);
  free_irq(IRQ_ADC, ts.dev);
  iounmap(base_addr);
  return -EIO;
 }

 printk(KERN_INFO "%s successfully loaded\n", s3c2440ts_name);

 /* All went ok, so register to the input system */
 input_register_device(ts.dev);
 
 return 0;
}

static int s3c2440ts_remove(struct device *dev)
{
 disable_irq(IRQ_ADC);
 disable_irq(IRQ_TC);
 free_irq(IRQ_TC, ts.dev);
 free_irq(IRQ_ADC, ts.dev);

 if (adc_clock) {
  clk_disable(adc_clock);
  //clk_unuse(adc_clock);
  clk_put(adc_clock);
  adc_clock = NULL;
 }
 
 input_unregister_device(ts.dev);
 iounmap(base_addr);

 return 0;
}

static struct device_driver s3c2440ts_driver = {
       .name           = "s3c2440-ts",
       .bus            = &platform_bus_type,
       .probe          = s3c2440ts_probe,
       .remove         = s3c2440ts_remove,
};


int __init s3c2440ts_init(void)
{
 return driver_register(&s3c2440ts_driver);
}

void __exit s3c2440ts_exit(void)
{
 driver_unregister(&s3c2440ts_driver);
}

module_init(s3c2440ts_init);
module_exit(s3c2440ts_exit);

MODULE_AUTHOR("Arnaud Patard <>");
MODULE_DESCRIPTION("s3c2440 touchscreen driver");
MODULE_LICENSE("GPL");
 

三.将s3c2440_ts.h文件拷贝到include/asm/arch-s3c2410/目录下,其内容为:

#ifndef __ASM_ARM_S3C2440_TS_H
#define __ASM_ARM_S3C2440_TS_H

struct s3c2440_ts_mach_info {
       int             delay;
       int             presc;
       int             oversampling_shift;
};

void __init set_s3c2440ts_info(struct s3c2440_ts_mach_info *hard_s3c2440ts_info);

#endif /* __ASM_ARM_S3C2440_TS_H */

四.在 arch/arm/mach-s3c2410/devs.c文件中添加如下几行

#include

/* Touchscreen */
static struct s3c2440_ts_mach_info s3c2440ts_info;

void __init set_s3c2440ts_info(struct s3c2440_ts_mach_info *hard_s3c2440ts_info)
{
 memcpy(&s3c2440ts_info, hard_s3c2440ts_info, sizeof(struct s3c2440_ts_mach_info));
}

EXPORT_SYMBOL(set_s3c2440ts_info);

struct platform_device s3c_device_ts = {
 .name    = "s3c2440-ts",
 .id    = -1,
 .dev              = {
   .platform_data = &s3c2440ts_info,
 }
};
EXPORT_SYMBOL(s3c_device_ts);

五.在arch/arm/mach-s3c2410/devs.h文件中添加:

extern struct platform_device s3c_device_ts;

六.在arch/arm/mach-s3c2410/mach-smdk2410.c中添加:

#include

static struct s3c2440_ts_mach_info s3c2440_ts_cfg __initdata = {
 .delay = 10000,
 //.delay = 200000,
 .presc = 49,
 .oversampling_shift = 2,
};

 在 smdk2440_devices[] 增加 &s3c_device_ts,
 在 smdk2440_machine_init()函数中调用 set_s3c2440ts_info(&s3c2440_ts_cfg);

七.在drivers/input/touchscreen/Kconfig中添加

config TOUCHSCREEN_S3C2440
 tristate "Samsung S3C2440 touchscreen input driver"
 depends on ARCH_S3C2440 && INPUT && INPUT_TOUCHSCREEN
 select SERIO
 help
   Say Y here if you have the s3c2440 touchscreen.

   If unsure, say N.

   To compile this driver as a module, choose M here: the
   module will be called s3c2440_ts.

config TOUCHSCREEN_S3C2440_DEBUG
 boolean "Samsung S3C2440 touchscreen debug messages"
 depends on TOUCHSCREEN_S3C2440
 help
   Select this if you want debug messages


八.在drivers/input/touchscreen/Makefile中添加:

 obj-$(CONFIG_TOUCHSCREEN_S3C2440) += s3c2440_ts.o


九.配置编译内核

点击看大图

点击看大图


十.创建设备文件
 根据你的配置情况创建相应的设备文件例如:
 mknod -m 666 ts -c 13 128 等
 
注: 因为这个驱动相对校简单,在实际应用中需要对其准确性和效率需要自己验证和改进.

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