读书人

6410之AD驱动与触摸屏共存(上)

发布时间: 2012-09-10 11:02:33 作者: rapoo

6410之AD驱动与触摸屏共存(下)

触摸屏驱动源码
#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <asm/io.h>#include <asm/irq.h>#include <mach/hardware.h>#include <plat/regs-adc.h>#include <mach/ts.h>#include <mach/irqs.h>#define CONFIG_TOUCHSCREEN_S3C_DEBUG#undef CONFIG_TOUCHSCREEN_S3C_DEBUG/* For ts->dev.id.version */#define S3C_TSVERSION0x0101#define WAIT4INT(x)  (((x)<<8) | \     S3C_ADCTSC_YM_SEN | S3C_ADCTSC_YP_SEN | S3C_ADCTSC_XP_SEN | \     S3C_ADCTSC_XY_PST(3))#define AUTOPST     (S3C_ADCTSC_YM_SEN | S3C_ADCTSC_YP_SEN | S3C_ADCTSC_XP_SEN | \     S3C_ADCTSC_AUTO_PST | S3C_ADCTSC_XY_PST(0))#define DEBUG_LVL    KERN_DEBUG/* Touchscreen default configuration */struct s3c_ts_mach_info s3c_ts_default_cfg __initdata = {                .delay = 5000,//10000,                .presc = 49,                .oversampling_shift = 4,//2,.resol_bit = 10};/* * Definitions & global arrays. */static char *s3c_ts_name = "S3C TouchScreen";static void __iomem *ts_base;static struct resource*ts_mem;static struct resource*ts_irq;static struct clk*ts_clock;static struct s3c_ts_info *ts;static int downflag=0;static void touch_timer_fire(unsigned long data){unsigned long data0;unsigned long data1;int updown;data0 = readl(ts_base+S3C_ADCDAT0);data1 = readl(ts_base+S3C_ADCDAT1);updown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));if (updown) {//printk("updown=1.\n");if (ts->count) {#ifdef CONFIG_TOUCHSCREEN_S3C_DEBUG{struct timeval tv;do_gettimeofday(&tv);printk(KERN_INFO "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts->xp, ts->yp);}#endif    if(downflag==0)                     {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);                     }                    else                    {                       // printk("downflag=1.ignore this data.\n");    downflag=0;                    }}ts->xp = 0;ts->yp = 0;ts->count = 0;writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_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), ts_base+S3C_ADCTSC);}}static struct timer_list touch_timer =TIMER_INITIALIZER(touch_timer_fire, 0, 0);static irqreturn_t stylus_updown(int irqno, void *param){unsigned long data0;unsigned long data1;int updown;data0 = readl(ts_base+S3C_ADCDAT0);data1 = readl(ts_base+S3C_ADCDAT1);updown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));#ifdef CONFIG_TOUCHSCREEN_S3C_DEBUG       printk(KERN_INFO "   %c\n",updown ? 'D' : 'U');#endif/* 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){downflag=1;//printk("touch_timer_fire(0)\n");touch_timer_fire(0);}if(ts->s3c_adc_con==ADC_TYPE_2) {       __raw_writel(0x0, ts_base+S3C_ADCCLRWK);        __raw_writel(0x0, ts_base+S3C_ADCCLRINT);}        return IRQ_HANDLED;}static irqreturn_t stylus_action(int irqno, void *param){unsigned long data0;unsigned long data1;//printk("stylus_action.\n");data0 = readl(ts_base+S3C_ADCDAT0);data1 = readl(ts_base+S3C_ADCDAT1);if(ts->resol_bit==12) {#if defined(CONFIG_TOUCHSCREEN_NEW)ts->yp += S3C_ADCDAT0_XPDATA_MASK_12BIT - (data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT);ts->xp += S3C_ADCDAT1_YPDATA_MASK_12BIT - (data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT);#else ts->xp += data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT;ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT;#endif}else {#if defined(CONFIG_TOUCHSCREEN_NEW)ts->yp += S3C_ADCDAT0_XPDATA_MASK - (data0 & S3C_ADCDAT0_XPDATA_MASK);ts->xp += S3C_ADCDAT1_YPDATA_MASK - (data1 & S3C_ADCDAT1_YPDATA_MASK);#elsets->xp += data0 & S3C_ADCDAT0_XPDATA_MASK;ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK;#endif}ts->count++;if (ts->count < (1<<ts->shift)) {writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);} else {mod_timer(&touch_timer, jiffies+1);writel(WAIT4INT(1), ts_base+S3C_ADCTSC);}if(ts->s3c_adc_con==ADC_TYPE_2) {       __raw_writel(0x0, ts_base+S3C_ADCCLRWK);        __raw_writel(0x0, ts_base+S3C_ADCCLRINT);}return IRQ_HANDLED;}static struct s3c_ts_mach_info *s3c_ts_get_platdata (struct device *dev){if (dev->platform_data != NULL)return (struct s3c_ts_mach_info *)dev->platform_data;return &s3c_ts_default_cfg;}/* * The functions for inserting/removing us as a module. */static int __init s3c_ts_probe(struct platform_device *pdev){struct resource *res;struct device *dev;struct input_dev *input_dev;struct s3c_ts_mach_info * s3c_ts_cfg;int ret, size;dev = &pdev->dev;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL) {dev_err(dev,"no memory resource specified\n");return -ENOENT;}size = (res->end - res->start) + 1;ts_mem = request_mem_region(res->start, size, pdev->name);if (ts_mem == NULL) {dev_err(dev, "failed to get memory region\n");ret = -ENOENT;goto err_req;}ts_base = ioremap(res->start, size);if (ts_base == NULL) {dev_err(dev, "failed to ioremap() region\n");ret = -EINVAL;goto err_map;}ts_clock = clk_get(&pdev->dev, "adc");if (IS_ERR(ts_clock)) {dev_err(dev, "failed to find watchdog clock source\n");ret = PTR_ERR(ts_clock);goto err_clk;}clk_enable(ts_clock);s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev);if ((s3c_ts_cfg->presc&0xff) > 0)writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xFF),\ts_base+S3C_ADCCON);elsewritel(0, ts_base+S3C_ADCCON);/* Initialise registers */if ((s3c_ts_cfg->delay&0xffff) > 0)writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);if (s3c_ts_cfg->resol_bit==12) {switch(s3c_ts_cfg->s3c_adc_con) {case ADC_TYPE_2:writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);break;case ADC_TYPE_1:writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT_1, ts_base+S3C_ADCCON);break;default:dev_err(dev, "Touchscreen over this type of AP isn't supported !\n");break;}}writel(WAIT4INT(0), ts_base+S3C_ADCTSC);ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);input_dev = input_allocate_device();if (!input_dev) {ret = -ENOMEM;goto err_alloc;}ts->dev = input_dev;ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);if (s3c_ts_cfg->resol_bit==12) {input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);}else {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, "input(ts)");ts->dev->name = s3c_ts_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 = S3C_TSVERSION;ts->shift = s3c_ts_cfg->oversampling_shift;ts->resol_bit = s3c_ts_cfg->resol_bit;ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;/* For IRQ_PENDUP */ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);if (ts_irq == NULL) {dev_err(dev, "no irq resource specified\n");ret = -ENOENT;goto err_irq;}ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts);if (ret != 0) {dev_err(dev,"s3c_ts.c: Could not allocate ts IRQ_PENDN !\n");ret = -EIO;goto err_irq;}/* For IRQ_ADC */ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);if (ts_irq == NULL) {dev_err(dev, "no irq resource specified\n");ret = -ENOENT;goto err_irq;}ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM, "s3c_action", ts);if (ret != 0) {dev_err(dev, "s3c_ts.c: Could not allocate ts IRQ_ADC !\n");ret =  -EIO;goto err_irq;}printk(KERN_INFO "%s got loaded successfully : %d bits\n", s3c_ts_name, s3c_ts_cfg->resol_bit);/* All went ok, so register to the input system */ret = input_register_device(ts->dev);if(ret) {dev_err(dev, "s3c_ts.c: Could not register input device(touchscreen)!\n");ret = -EIO;goto fail;}return 0;fail:free_irq(ts_irq->start, ts->dev);free_irq(ts_irq->end, ts->dev);err_irq:input_free_device(input_dev);kfree(ts);err_alloc:clk_disable(ts_clock);clk_put(ts_clock);err_clk:iounmap(ts_base);err_map:release_resource(ts_mem);kfree(ts_mem);err_req:return ret;}static int s3c_ts_remove(struct platform_device *dev){printk(KERN_INFO "s3c_ts_remove() of TS called !\n");disable_irq(IRQ_ADC);disable_irq(IRQ_PENDN);free_irq(IRQ_PENDN, ts->dev);free_irq(IRQ_ADC, ts->dev);if (ts_clock) {clk_disable(ts_clock);clk_put(ts_clock);ts_clock = NULL;}input_unregister_device(ts->dev);iounmap(ts_base);return 0;}#ifdef CONFIG_PMstatic unsigned int adccon, adctsc, adcdly;static int s3c_ts_suspend(struct platform_device *dev, pm_message_t state){adccon = readl(ts_base+S3C_ADCCON);adctsc = readl(ts_base+S3C_ADCTSC);adcdly = readl(ts_base+S3C_ADCDLY);disable_irq(IRQ_ADC);disable_irq(IRQ_PENDN);clk_disable(ts_clock);return 0;}static int s3c_ts_resume(struct platform_device *pdev){clk_enable(ts_clock);writel(adccon, ts_base+S3C_ADCCON);writel(adctsc, ts_base+S3C_ADCTSC);writel(adcdly, ts_base+S3C_ADCDLY);writel(WAIT4INT(0), ts_base+S3C_ADCTSC);enable_irq(IRQ_ADC);enable_irq(IRQ_PENDN);return 0;}#else#define s3c_ts_suspend NULL#define s3c_ts_resume  NULL#endifstatic struct platform_driver s3c_ts_driver = {       .probe          = s3c_ts_probe,       .remove         = s3c_ts_remove,       .suspend        = s3c_ts_suspend,       .resume         = s3c_ts_resume,       .driver= {.owner= THIS_MODULE,.name= "s3c-ts",},};static char banner[] __initdata = KERN_INFO "S3C Touchscreen driver, (c) 2008 Samsung Electronics\n";static int __init s3c_ts_init(void){printk(banner);return platform_driver_register(&s3c_ts_driver);}static void __exit s3c_ts_exit(void){platform_driver_unregister(&s3c_ts_driver);}module_init(s3c_ts_init);module_exit(s3c_ts_exit);MODULE_AUTHOR("Samsung AP");MODULE_DESCRIPTION("S3C touchscreen driver");MODULE_LICENSE("GPL");
增加互斥量源码

#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/clk.h>

#include <asm/io.h>#include <asm/irq.h>#include <mach/hardware.h>

#include <plat/regs-adc.h>#include <mach/ts.h>#include <mach/irqs.h>

#define CONFIG_TOUCHSCREEN_S3C_DEBUG#undef CONFIG_TOUCHSCREEN_S3C_DEBUG

/* For ts->dev.id.version */#define S3C_TSVERSION 0x0101

#define WAIT4INT(x) (((x)<<8) | \ S3C_ADCTSC_YM_SEN | S3C_ADCTSC_YP_SEN | S3C_ADCTSC_XP_SEN | \ S3C_ADCTSC_XY_PST(3))

#define AUTOPST (S3C_ADCTSC_YM_SEN | S3C_ADCTSC_YP_SEN | S3C_ADCTSC_XP_SEN | \ S3C_ADCTSC_AUTO_PST | S3C_ADCTSC_XY_PST(0))

#define DEBUG_LVL KERN_DEBUG

/* Touchscreen default configuration */struct s3c_ts_mach_info s3c_ts_default_cfg __initdata = { .delay = 5000,//10000, .presc = 49, .oversampling_shift = 4,//2, .resol_bit = 10};

/* * Definitions & global arrays. */static char *s3c_ts_name = "S3C TouchScreen";static void __iomem *ts_base;static struct resource *ts_mem;static struct resource *ts_irq;static struct clk *ts_clock;static struct s3c_ts_info *ts;

static int downflag=0;

#ifdef CONFIG_FORLINX6410_ADC

DEFINE_SEMAPHORE(ADC_LOCK);/* Indicate who is using the ADC controller */#define LOCK_FREE 0#define LOCK_TS 1#define LOCK_ADC 2static int adc_lock_id = LOCK_FREE;

#define ADC_free() (adc_lock_id == LOCK_FREE)#define ADC_locked4TS() (adc_lock_id == LOCK_TS)

static inline int s3c_ts_adc_lock(int id) { int ret;

ret = down_trylock(&ADC_LOCK); if (!ret) { adc_lock_id = id; }

return ret;}

static inline void s3c_ts_adc_unlock(void) { adc_lock_id = 0; up(&ADC_LOCK);}

static unsigned int _adccon, _adctsc, _adcdly;

int X6410_adc_acquire_io(void) { int ret;

ret = s3c_ts_adc_lock(LOCK_ADC); if (!ret) { _adccon = readl(ts_base + S3C_ADCCON); _adctsc = readl(ts_base + S3C_ADCTSC); _adcdly = readl(ts_base + S3C_ADCDLY);

printk("forlinx debug****X6410_adc_acquire_io();.\n");

}

return ret;}EXPORT_SYMBOL(X6410_adc_acquire_io);

void X6410_adc_release_io(void) { writel(_adccon, ts_base + S3C_ADCCON); writel(_adctsc, ts_base + S3C_ADCTSC); writel(_adcdly, ts_base + S3C_ADCDLY); writel(WAIT4INT(0), ts_base + S3C_ADCTSC);

s3c_ts_adc_unlock();

printk("forlinx debug*****X6410_adc_release_io();.\n");

}

EXPORT_SYMBOL(X6410_adc_release_io);

#endif

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

#ifdef CONFIG_FORLINX6410_ADC if (!ADC_locked4TS()) { /* Note: pen UP interrupt detected and handled, the lock is released, * so do nothing in the timer which started by ADC ISR. */ return; }#endif

data0 = readl(ts_base+S3C_ADCDAT0); data1 = readl(ts_base+S3C_ADCDAT1);

pendown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));

if (pendown) { //down //printk("pendown=1.\n"); if (ts->count) {

#ifdef CONFIG_TOUCHSCREEN_S3C_DEBUG { struct timeval tv; do_gettimeofday(&tv); printk(KERN_INFO "T: %06d, X: %03ld, Y: %03ld\n", (int)tv.tv_usec, ts->xp, ts->yp); }#endif if(downflag==0) { 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); } else { // printk("downflag=1.ignore this data.\n"); downflag=0; } }

ts->xp = 0; ts->yp = 0; ts->count = 0;

writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC); writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON); } else {

//up

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), ts_base+S3C_ADCTSC);

#ifdef CONFIG_FORLINX6410_ADC if (ADC_locked4TS()) { s3c_ts_adc_unlock(); printk("forlinx debug*****s3c_ts_adc_unlock();.\n"); }#endif }

}

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

static irqreturn_t stylus_updown(int irqno, void *param){ unsigned long data0; unsigned long data1;

#ifdef CONFIG_FORLINX6410_ADC if (!ADC_locked4TS()) { if (s3c_ts_adc_lock(LOCK_TS)) { /* Locking ADC controller failed */ printk("Lock ADC failed, %d\n", adc_lock_id); return IRQ_HANDLED; }

printk("forlinx debug***** s3c_ts_adc_lock(LOCK_TS);.\n"); }#endif

data0 = readl(ts_base+S3C_ADCDAT0); data1 = readl(ts_base+S3C_ADCDAT1);

/* 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. */

touch_timer_fire(0);

if(ts->s3c_adc_con==ADC_TYPE_2) { __raw_writel(0x0, ts_base+S3C_ADCCLRWK); __raw_writel(0x0, ts_base+S3C_ADCCLRINT); } return IRQ_HANDLED;}

static irqreturn_t stylus_action(int irqno, void *param){ unsigned long data0; unsigned long data1;

#ifdef CONFIG_FORLINX6410_ADC if (!ADC_locked4TS()) { if (ADC_free()) { printk("Unexpected\n");

/* Clear ADC interrupt */ __raw_writel(0x0, ts_base + S3C_ADCCLRINT); }

return IRQ_HANDLED; }#endif

//printk("stylus_action.\n");

data0 = readl(ts_base+S3C_ADCDAT0); data1 = readl(ts_base+S3C_ADCDAT1);

if(ts->resol_bit==12) {#if defined(CONFIG_TOUCHSCREEN_NEW) ts->yp += S3C_ADCDAT0_XPDATA_MASK_12BIT - (data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT); ts->xp += S3C_ADCDAT1_YPDATA_MASK_12BIT - (data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT);#else ts->xp += data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT; ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT;#endif } else {#if defined(CONFIG_TOUCHSCREEN_NEW) ts->yp += S3C_ADCDAT0_XPDATA_MASK - (data0 & S3C_ADCDAT0_XPDATA_MASK); ts->xp += S3C_ADCDAT1_YPDATA_MASK - (data1 & S3C_ADCDAT1_YPDATA_MASK);#else ts->xp += data0 & S3C_ADCDAT0_XPDATA_MASK; ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK;#endif }

ts->count++;

if (ts->count < (1<<ts->shift)) { writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC); writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON); } else { mod_timer(&touch_timer, jiffies+1); writel(WAIT4INT(1), ts_base+S3C_ADCTSC); }

if(ts->s3c_adc_con==ADC_TYPE_2) { __raw_writel(0x0, ts_base+S3C_ADCCLRWK); __raw_writel(0x0, ts_base+S3C_ADCCLRINT); } return IRQ_HANDLED;}

static struct s3c_ts_mach_info *s3c_ts_get_platdata (struct device *dev){ if (dev->platform_data != NULL) return (struct s3c_ts_mach_info *)dev->platform_data;

return &s3c_ts_default_cfg;}

/* * The functions for inserting/removing us as a module. */static int __init s3c_ts_probe(struct platform_device *pdev){ struct resource *res; struct device *dev; struct input_dev *input_dev; struct s3c_ts_mach_info * s3c_ts_cfg; int ret, size;

dev = &pdev->dev;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(dev,"no memory resource specified\n"); return -ENOENT; }

size = (res->end - res->start) + 1; ts_mem = request_mem_region(res->start, size, pdev->name); if (ts_mem == NULL) { dev_err(dev, "failed to get memory region\n"); ret = -ENOENT; goto err_req; }

ts_base = ioremap(res->start, size); if (ts_base == NULL) { dev_err(dev, "failed to ioremap() region\n"); ret = -EINVAL; goto err_map; } ts_clock = clk_get(&pdev->dev, "adc"); if (IS_ERR(ts_clock)) { dev_err(dev, "failed to find watchdog clock source\n"); ret = PTR_ERR(ts_clock); goto err_clk; }

clk_enable(ts_clock);

s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev); if ((s3c_ts_cfg->presc&0xff) > 0) writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xff), ts_base+S3C_ADCCON); else writel(0, ts_base+S3C_ADCCON);

/* Initialise registers */ if ((s3c_ts_cfg->delay&0xffff) > 0) writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);

if (s3c_ts_cfg->resol_bit==12) { switch(s3c_ts_cfg->s3c_adc_con) { case ADC_TYPE_2: writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON); break;

case ADC_TYPE_1: writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT_1, ts_base+S3C_ADCCON); break; default: dev_err(dev, "Touchscreen over this type of AP isn't supported !\n"); break; } } writel(WAIT4INT(0), ts_base+S3C_ADCTSC);

ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL); input_dev = input_allocate_device();

if (!input_dev) { ret = -ENOMEM; goto err_alloc; } ts->dev = input_dev;

ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);

if (s3c_ts_cfg->resol_bit==12) { input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0); input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0); } else { 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, "input(ts)");

ts->dev->name = s3c_ts_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 = S3C_TSVERSION;

ts->shift = s3c_ts_cfg->oversampling_shift; ts->resol_bit = s3c_ts_cfg->resol_bit; ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con; /* For IRQ_PENDUP */ ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (ts_irq == NULL) { dev_err(dev, "no irq resource specified\n"); ret = -ENOENT; goto err_irq; }

ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts); if (ret != 0) { dev_err(dev,"s3c_ts.c: Could not allocate ts IRQ_PENDN !\n"); ret = -EIO; goto err_irq; }

/* For IRQ_ADC */ ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1); if (ts_irq == NULL) { dev_err(dev, "no irq resource specified\n"); ret = -ENOENT; goto err_irq; }

ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM | IRQF_SHARED, "s3c_action", ts); if (ret != 0) { dev_err(dev, "s3c_ts.c: Could not allocate ts IRQ_ADC !\n"); ret = -EIO; goto err_irq; }

printk(KERN_INFO "%s got loaded successfully : %d bits\n", s3c_ts_name, s3c_ts_cfg->resol_bit);

/* All went ok, so register to the input system */ ret = input_register_device(ts->dev); if(ret) { dev_err(dev, "s3c_ts.c: Could not register input device(touchscreen)!\n"); ret = -EIO; goto fail; }

return 0;

fail: free_irq(ts_irq->start, ts->dev); free_irq(ts_irq->end, ts->dev); err_irq: input_free_device(input_dev); kfree(ts);

err_alloc: clk_disable(ts_clock); clk_put(ts_clock); err_clk: iounmap(ts_base);

err_map: release_resource(ts_mem); kfree(ts_mem);

err_req: return ret;}

static int s3c_ts_remove(struct platform_device *dev){ printk(KERN_INFO "s3c_ts_remove() of TS called !\n");

disable_irq(IRQ_ADC); disable_irq(IRQ_PENDN); free_irq(IRQ_PENDN, ts->dev); free_irq(IRQ_ADC, ts->dev);

if (ts_clock) { clk_disable(ts_clock); clk_put(ts_clock); ts_clock = NULL; }

input_unregister_device(ts->dev); iounmap(ts_base);

return 0;}

#ifdef CONFIG_PMstatic unsigned int adccon, adctsc, adcdly;

static int s3c_ts_suspend(struct platform_device *dev, pm_message_t state){ adccon = readl(ts_base+S3C_ADCCON); adctsc = readl(ts_base+S3C_ADCTSC); adcdly = readl(ts_base+S3C_ADCDLY);

disable_irq(IRQ_ADC); disable_irq(IRQ_PENDN); clk_disable(ts_clock);

return 0;}

static int s3c_ts_resume(struct platform_device *pdev){ clk_enable(ts_clock);

writel(adccon, ts_base+S3C_ADCCON); writel(adctsc, ts_base+S3C_ADCTSC); writel(adcdly, ts_base+S3C_ADCDLY); writel(WAIT4INT(0), ts_base+S3C_ADCTSC);

enable_irq(IRQ_ADC); enable_irq(IRQ_PENDN); return 0;}#else#define s3c_ts_suspend NULL#define s3c_ts_resume NULL#endif

static struct platform_driver s3c_ts_driver = { .probe = s3c_ts_probe, .remove = s3c_ts_remove, .suspend = s3c_ts_suspend, .resume = s3c_ts_resume, .driver = { .owner = THIS_MODULE, .name = "s3c-ts", },};

static char banner[] __initdata = KERN_INFO "S3C Touchscreen driver, (c) 2008 Samsung Electronics\n";

static int __init s3c_ts_init(void){ printk(banner); return platform_driver_register(&s3c_ts_driver);}

static void __exit s3c_ts_exit(void){ platform_driver_unregister(&s3c_ts_driver);}

module_init(s3c_ts_init);module_exit(s3c_ts_exit);

MODULE_AUTHOR("Samsung AP");MODULE_DESCRIPTION("S3C touchscreen driver");MODULE_LICENSE("GPL");


读书人网 >移动开发

热点推荐