首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

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

2012-09-10 
6410之AD驱动与触摸屏共存(下)触摸屏驱动源码#include linux/errno.h#include linux/kernel.h#include

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");


 

热点排行