s3c2410触摸板的驱动程序

原创 2011年11月01日 09:03:47
#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 <asm/arch/regs-gpio.h>

struct s3c_adc_regs {
    unsigned long adccon;
    unsigned long adctsc;
    unsigned long adcdly;
    unsigned long adcdat0;
    unsigned long adcdat1;
};

static struct input_dev *s3c_ts_dev;
static struct s3c_adc_regs *s3c_adc_regs;


static struct timer_list s3c_ts_timer;
//等待触摸笔的按下
static void enter_wait_pen_down(void)
{
    s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}

static void enter_wait_pen_up(void)
{
    s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
}
//测量xy的值
static void enter_measure_xy_mode(void)
{
    s3c_adc_regs->adctsc = (1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2);
}

static void start_adc(void)
{
    s3c_adc_regs->adccon |= (1<<0);
}
//时间函数,时间到的时间,自动启动xy的转换,开始adc
static void s3c_ts_timer_function(unsigned long h)
{
    enter_measure_xy_mode();
    start_adc();
}


static irqreturn_t pen_down_up_isr(int irq, void *devid)
{
    static int cnt = 0;

    if (s3c_adc_regs->adcdat0 & (1<<15))
    {
        //printk("pen_down_up_isr up: %d\n", ++cnt);

        /* 进入"等待中断模式": 等待按下 */
        enter_wait_pen_down();
        
        /*上报事件 ,完成一次上报事件*/
        input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
        input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
        input_sync(s3c_ts_dev);

    }
    else
    {
#if 0
        printk("pen_down_up_isr down: %d\n", ++cnt);

        /* 进入"等待中断模式": 等待松开 */
        s3c_adc_regs->adctsc = (1<<8) | (1<<7) | (1<<6) | (0<<5) | (1 << 4) | (0 << 3) | (3<<0);
#endif
        //printk("pen_down_up_isr down: %d\n", ++cnt);
        enter_measure_xy_mode();
        start_adc();
    }
    
    return IRQ_HANDLED;
}
//  过滤  让定位更准确
static int s3c_ts_filtering(int *px, int *py)
{
    int avr_x, avr_y;
    int dx, dy;

#define FILTER_LIMIT 25

    avr_x = (px[0] + px[1]) / 2;
    avr_y = (py[0] + py[1]) / 2;

    dx = (px[2] > avr_x) ? (px[2] - avr_x) : (avr_x - px[2]);
    dy = (py[2] > avr_y) ? (py[2] - avr_y) : (avr_y - py[2]);

    if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
        return 0;

    avr_x = (px[1] + px[2]) / 2;
    avr_y = (py[1] + py[2]) / 2;

    dx = (px[3] > avr_x) ? (px[3] - avr_x) : (avr_x - px[3]);
    dy = (py[3] > avr_y) ? (py[3] - avr_y) : (avr_y - py[3]);

    if ((dx > FILTER_LIMIT) || (dy > FILTER_LIMIT))
        return 0;

    return 1;
}


static irqreturn_t adc_isr(int irq, void *devid)
{
    static int cnt = 0;    
    static int xs[4];
    static int ys[4];
    static int x = 0, y = 0;
//    static int pre_x = 0, pre_y = 0;
    int data0, data1;
    
    //printk("adc_isr : %d\n", ++cnt);

    data0 = s3c_adc_regs->adcdat0;
    data1 = s3c_adc_regs->adcdat1;

    if (data0 & (1<<15))
    {
        /* 已经松开 */
        enter_wait_pen_down();

        input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 0);
        input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 0);
        input_sync(s3c_ts_dev);

        x = y = cnt = 0;
    }
    else
    {
        //printk("x = %d, y = %d\n", x, y);
        x += (data0 & 0x3ff);
        y += (data1 & 0x3ff);
        xs[cnt] = (data0 & 0x3ff);
        ys[cnt] = (data0 & 0x3ff);
        
        cnt++;
        
        if (cnt == 4)
        {
            if (s3c_ts_filtering(xs, ys))
            {
                input_event(s3c_ts_dev, EV_ABS, ABS_X, x/4);
                input_event(s3c_ts_dev, EV_ABS, ABS_Y, y/4);
                input_event(s3c_ts_dev, EV_ABS, ABS_PRESSURE, 1);
                input_event(s3c_ts_dev, EV_KEY, BTN_TOUCH, 1);
                input_sync(s3c_ts_dev);
            }

            x = y = cnt = 0;
            
            /* 进入"等待中断模式": 等待松开 */
            enter_wait_pen_up();
            
            mod_timer(&s3c_ts_timer, jiffies + HZ/100);
        }
        else
        {
            enter_measure_xy_mode();
            start_adc();
        }

    }

    return IRQ_HANDLED;
}

static int s3c_ts_init(void)
{
    unsigned long *gpgcon = ioremap(0x56000060, 4);

    /* 1. 分配一个input_dev结构体 */
    s3c_ts_dev = input_allocate_device();

    /* 2. 设置 */

    /* 2.1 能产生哪类事件 */
    __set_bit(EV_KEY, s3c_ts_dev->evbit);
    __set_bit(EV_ABS, s3c_ts_dev->evbit);

    /* 2.1 能产生这类事件里的哪些 */
    __set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
    /*触摸屏的初始化*/
    input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
    input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
    input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

    s3c_ts_dev->name = "s3c_ts";

    /* 3. 注册 */
    input_register_device(s3c_ts_dev);

    /* 4. 硬件相关的操作 */
    /* CLKCON  的使能*/
    clk_enable(clk_get(NULL, "adc"));

    /* 配置引脚用于触摸屏 */
    *gpgcon |= 0xff000000;
    iounmap(gpgcon);

    s3c_adc_regs = ioremap(0x58000000, 1024);

    /* bit14: A/D converter prescaler enable
     * bit[13:6]: A/D converter prescaler value,
     *            ADC CLK = PCLK/(49+1)
     */
    s3c_adc_regs->adccon = (1<<14) | (49 << 6);

    s3c_adc_regs->adcdly = 0xffff;
//添加定时器
    init_timer(&s3c_ts_timer);
    s3c_ts_timer.expires = 0;
    s3c_ts_timer.function = s3c_ts_timer_function;
    add_timer(&s3c_ts_timer);

    /* 进入"等待中断模式": 等待按下 */
    enter_wait_pen_down();
    
    request_irq(IRQ_TC, pen_down_up_isr, IRQF_SHARED, "touch_pen", 1);
    request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc_done", 1);
    
    return 0;
}

static void s3c_ts_exit(void)
{
    free_irq(IRQ_ADC, 1);
    free_irq(IRQ_TC, 1);
    input_unregister_device(s3c_ts_dev);
    input_free_device(s3c_ts_dev);
}

module_init(s3c_ts_init);
module_exit(s3c_ts_exit);


MODULE_LICENSE("GPL");


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

s3c2410板的linux下AD驱动程序

  • 2009年01月06日 14:21
  • 2KB
  • 下载

s3c2410 linux 触摸屏驱动程序分析

//******************************************************* //* 2007.6.26 //************************...

Linux下IIS音频驱动程序分析(基于S3C2410+ UDA1341)

原文地址::http://os.chinaunix.net/a2009/0901/997/000000997053.shtml     armlinux学习笔记--IIS音频驱动程序分析[z] ...

S3C2410的ADC驱动程序

驱动模块程序: #include #include #include #include #include #include #include    /* prin...

linux下S3C2410的DMA驱动程序开发

网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的...

s3c2410键盘驱动程序分析

在fs2410开发板上矩阵键盘的硬件连接图如下:       连接矩阵键盘的8个IO口与核心板IO依次对应为:行:EINT0         GPF0  EINT2      GPF2  EINT11...

S3C2410的linux 下DMA驱动程序开发

网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的...

S3C2410TFT_LCD显示的驱动程序设计

  • 2009年11月06日 12:52
  • 605KB
  • 下载

s3c2410驱动程序Demo

  • 2013年04月02日 22:50
  • 2KB
  • 下载

ARM 中断驱动程序的开发流程(以s3c2440开发板为例)

为便于管理中断和节约CPU管脚,在cpu与中断源之间都会有中断控制器,一般的ARM芯片内部都集成了片上中断控制器。 以s3c2440开发板的按键中断为例来说明ARM中断的开发过程。 当一个设备产生...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:s3c2410触摸板的驱动程序
举报原因:
原因补充:

(最多只允许输入30个字)