s3c2410触摸板的驱动程序

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值