Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265654
  • 博文数量: 25
  • 博客积分: 329
  • 博客等级: 一等列兵
  • 技术积分: 1380
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-24 09:43
文章分类

全部博文(25)

文章存档

2014年(4)

2013年(12)

2012年(9)

分类: LINUX

2012-08-25 09:40:24

 

由于触摸屏是一个输入设备,故可以使用输入子系统的这一套代码的框架来实现。在触摸屏中设计中断,故也应该注册中断。驱动程序的设计思路是:正常状态下,触摸屏处于等待按下中断状态,当触摸屏被按下时,产生触摸屏中断,设置触摸屏处于等待弹起中断的状态,并在中断处理函数中启动ADC转换,当ADC转换完成后,产生ADC中断,在ADC中断处理函数中完成读出坐标值并上报触摸屏事件。当触摸屏弹起时,产生弹起中断,在中断处理函数中上报触摸屏弹起事件。为了解决触摸屏的滑动问题,我们加入定时器,在触摸屏保存按下的状态时,每隔一段时间重新启动ADC转换器,转换完成读出坐标值,上报事件。

触摸屏驱动程序设计步骤与输入子系统的相似。

代码分析:

/* 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);

/* 设置、初始化、添加定时器 */

init_timer(&s3c_tc_timer);

s3c_tc_timer.function = s3c_tc_fun;

add_timer(&s3c_tc_timer);

/* 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);

/* 注册TC中断和ADC中断 */

request_irq(IRQ_TC,touch_up_down_irq,IRQF_SAMPLE_RANDOM,"s3c_ts",NULL);

request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "s3c_adc", NULL);

/*

* 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断

*/

s3c_ts_regs->adcdly = 0xffff;

enter_wait_pen_down_mode();

/* 触摸屏中断处理函数 */

static irqreturn_t touch_up_down_irq(int irq, void *dev_id)

{

/* 判断产生触摸屏中断时时,触摸屏是否任处于按下状态 */

if(s3c_tc_regs->adcdat0 & (1<<15))

{

/* 若已弹起,则上报触摸屏已经弹起 */

input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);

input_sync(s3c_ts_dev);

enter_wait_down_irq();

}

else

{

/* 若任处于按下状态,则设置ADC的转换模式为自动转换自动转换XY坐标的模式 */

enter_measure_xy_mode();

start_adc();

}

return IRQ_RETVAL(IRQ_HANDLED);

}

在ADC中断处理函数中:

input_report_abs(s3c_ts_dev, ABS_X, adcdat0 & 0x3ff);

input_report_abs(s3c_ts_dev, ABS_Y, adcdat1 & 0x3ff);

input_report_key(s3c_ts_dev, BTN_TOUCH, 1);

input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);

input_sync(s3c_ts_dev);

enter_wait_up_irq();

/* 重新设计定时器的超时时间 */

mod_timer(&s3c_tc_timer, jiffies + HZ/100);

在定时器的超时处理函数中只做一件事:

启动ADC转换器。

 

以上内容全是本人凭个人理解写出的:如果错误请多包涵,若能指出,本人将万分感激。

阅读(2277) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~