Linux输入子系统之触摸屏驱动2

本文详细介绍了Linux系统下触摸屏驱动的工作流程,包括按下中断处理、ADC坐标转换、事件上报及定时器处理长按和滑动。通过编译内核模块并进行测试,展示了从模块加载到触摸屏事件的读取,以及tslib库的配置和使用,用于校准和测试触摸屏功能。
摘要由CSDN通过智能技术生成

触摸屏使用过程
1.按下,产生中断pen_down_up_irq
2.在中断处理程序里面启动ADC,转换坐标(x,y)
3.ADC结束之后,产生ADC中断
4.在ADC中断处理函数里面上报事件(input_event),启动定时器。
5.定时器时间到(处理长按、滑动)
5.1如果触摸笔松开,进入等待按下模式
5.2否则,再次再一次测量x,y,再次启动ADC

初始化函数

static int s3c_ts_init(void)
{
    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);    //设备,最小值,最大值,
    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);


    /* 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);   //按下触摸屏,产生中断,pen_down_up_irq:中断处理函数
    request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);       //ADC完成之后产生的中断,adc_irq:中断处理函数

    /* 优化措施1: 
     * 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断
     */
    s3c_ts_regs->adcdly = 0xffff;

    /* 优化措施5: 使用定时器处理长按,滑动的情况
     * 
     */
    init_timer(&ts_timer);     //初始化,传入定时器地址&ts_timer
    ts_timer.function = s3c_ts_timer_function;  //超时函数
    add_timer(&ts_timer);   //把定时器告诉内核,当超时后,s3c_ts_timer_function被调用

    enter_wait_pen_down_mode();   //设置等待触摸笔按下模式,让寄存器ADCTSC=0xd3,进入等待中断模式Waiting for Interrupt Mode

    return 0;
}

按键按下后,产生的中断函数
pen_down_up_irq()

static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
       /*如何判断按下还是松开?  ADCDAT0的bit[15],0表示按下,1表示松开
         松开的时候进入等待按下模式enter_wait_pen_down_mode(),这样他就继续处理下一次。
              */
    if (s3c_ts_regs->adcdat0 & (1<<15))   //松开
    {
        //printk("pen up\n");
        input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);    //上报事件,ABS_PRESSURE压力值为0
        input_report_key(s3c_ts_dev, BTN_TOUCH, 0);    //BTN_TOUCH表示按键类事件,没有按下按键
        input_sync(s3c_ts_dev);
        enter_wait_pen_down_mode();   //触摸笔按下模式
    }
    else    //按下
    {
        //printk("pen down\n");
        //enter_wait_pen_up_mode();
        enter_measure_xy_mode();  //测量x,y坐标模式
        start_adc();     //启动ADC
    }
    return IRQ_HANDLED;
}

进入测量x,y坐标模式


static void enter_measure_xy_mode(void)
{
    s3c_ts_regs->adctsc = (1<<3)|(1<<2);   //bit[3]=1 禁止上拉使能,上拉电阻要断开,bit[2]=1设置模式3自动(连续)的x/y坐标转换模式
}

启动ADC


static void start_adc(void)
{
    s3c_ts_regs->adccon |= (1<<0);  //设置启动ADCCON寄存器bit[0]=1,就启动ADC
}

ADC结束,产生ADC中断


static irqreturn_t adc_irq(int irq, void *dev_id)      //ADC 完成之后,产生一个中断
{
    static int cnt = 0;
    static int x[4], y[4];
    int adcdat0, adcdat1;


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

    if (s3c_ts_regs->adcdat0 & (1<<15))     //如果已经松开
    {

        cnt = 0;
        input_report_abs(s3c_ts_dev,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值