有关触摸屏JZ2440——s3c_ts驱动程序

来源:互联网 发布:中国科协网络平台 编辑:程序博客网 时间:2024/06/05 17:06
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <mach/gpio-samsung.h>
#include<linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
////
#include <linux/input.h>
#include <linux/clk.h>
#define IRQF_SAMPLE_RANDOM 0x00000040
struct s3c_ts_regs {
    unsigned long adccon;
    unsigned long adctsc;
    unsigned long adcdly;
    unsigned long adcdat0;
    unsigned long adcdat1;
    unsigned long adcupdn;
};


static struct input_dev *s3c_ts_dev;/*定义一个输入设备来表示我们的触摸屏设备*/
static volatile struct s3c_ts_regs *s3c_ts_regs;


static void enter_wait_pen_down_mode(void)
{
    s3c_ts_regs->adctsc = 0xd3;//设置触摸屏为等待中断模式,等待触摸笔被按下(触笔按下触发中断)
}


static void enter_wait_pen_up_mode(void)
{
    s3c_ts_regs->adctsc=0x1d3;//设置触摸屏为等待中断模式,等待触摸笔被抬起(触笔抬起触发中断)


}


static void enter_measure_xy_mode(void)
{

    s3c_ts_regs->adctsc = ((1<<3)|(1<<2));//XP上拉无效,自动(顺序)得到X、Y坐标
}


static void start_adc(void)
{
    s3c_ts_regs->adccon |=(1<<0); //   设置AD开始转换  当硬件启动ADC转换时,该位被清0

}


static irqreturn_t pen_down_up_irq(int irq,void *dev_id)
{
    if(s3c_ts_regs->adcdat0 & (1<<15))//等待AD转换结束
        {
            printk("pen up\n");
            enter_wait_pen_up_mode();
            input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
            input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
            input_sync(s3c_ts_dev);
            enter_wait_pen_down_mode();

        }
    else
        {
            printk("pen down\n");
            enter_wait_pen_down_mode();
            enter_measure_xy_mode();
            start_adc();
        }
    return IRQ_HANDLED;


}



static irqreturn_t adc_irq(int irq,void *dev_id )
{
    static int cnt=0;
    int adcdat0,adcdat1;
    static int x[1],y[1];
    printk("adc_irq init \n");

    
/* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */
    adcdat0 =s3c_ts_regs->adcdat0;
    adcdat1 =s3c_ts_regs->adcdat1;
    x[0]=adcdat0 & 0x3ff;
    y[0]=adcdat1 & 0x3ff;

    if(s3c_ts_regs->adcdat0 &(1<<15))//等待AD转换结束
        {
            input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
            input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
            input_sync(s3c_ts_dev);

            enter_wait_pen_down_mode();//进入等待笔落下中断模式
        }

    else{
            //printk("adc_irq cnt=%d,x=%d,y=%d\n",++cnt,adcdat0 & 0x3ff,adcdat1 & 0x3ff);
            input_report_abs(s3c_ts_dev, ABS_X, x[0]);//ABS绝对坐标
            input_report_abs(s3c_ts_dev, ABS_Y, y[0]);
            input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
            input_report_key(s3c_ts_dev, BTN_TOUCH, 1);//用于给上层上报一个按键动作
            input_sync(s3c_ts_dev);//用来告诉上层,本次的事件已经完成了.


            enter_wait_pen_up_mode();//进入等待笔抬起中断模式
        
        }
    return IRQ_HANDLED;
}


/*
static void s3c_ts_init(void)
{
    struct clk* clk;
    
    s3c_ts_dev=input_allocate_device();
    
    set_bit(EV_KEY, s3c_ts_dev->evbit);
    set_bit(EV_ABS, s3c_ts_dev->evbit);

    
    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, 0x3FF, 0, 0);

    input_register_device(s3c_ts_dev);

    clk =clk_get(NULL,"adc");
    clk_enable(clk);

    
    s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
    s3c_ts_regs->adccon = (1<<14)|(49<<6);


    request_irq(IRQ_TC, pen_down_up_irq, IRQ_SAMPLE_RANDOM, "ts_pen", NULL);
    request_irq(IRQ_ADC, adc_irq, IRQF_SHARED, "adc", NULL);

    s3c_ts_regs->adcdly=0xffff;

    enter_wait_pen_down_mode;


    return 0;
        
    
}*/
static int s3c_ts_init(void)
{
    printk("s3c_ts_init \n");

    struct clk* clk;
    
    /* 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.2 能产生这类事件里的哪些事件=能产生按键类的触摸屏事件 */
    set_bit(BTN_TOUCH, s3c_ts_dev->keybit);

    input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);//设置X方向最大最小值
    input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);//设置Y方向 最大最小值
    input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);//压力方向,压力0 1 要么按下要么松开


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

    /* 4. 硬件相关的操作 */
    /* 4.1 使能时钟(CLKCON[15]) */
    clk = clk_get(NULL, "adc");
    clk_enable(clk);
    
    /* 4.2 设置S3C2440的ADC/TS寄存器 */
    s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));

    /* bit[14]  : 1-A/D converter prescaler enable
     * bit[13:6]: A/D converter prescaler value,
     *            49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz
     * bit[0]: A/D conversion starts by enable. 先设为0
     */
    s3c_ts_regs->adccon = (1<<14)|(49<<6);

    request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
    request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
    /* 优化错施1:
     * 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断
     */
    s3c_ts_regs->adcdly = 0xffff;
    

    enter_wait_pen_down_mode();
    
    return 0;
}

static void s3c_ts_exit(void)
{
    printk("s3c_ts_exit\n");
    free_irq(IRQ_TC, NULL);
    iounmap(s3c_ts_regs);
    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");
0 0
原创粉丝点击