分类: 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转换器。
以上内容全是本人凭个人理解写出的:如果错误请多包涵,若能指出,本人将万分感激。