想要实现Linux下触摸屏控制LCD屏的背光,即一段时间不点击触摸屏,LCD关掉背光,当点击触摸屏时就点亮背光,想一下,应该是在触摸屏的驱动中实现,所以,先来分析触摸屏驱动的源码(drivers/input/touchscreen/s3c2410_ts.c)。
static int __init s3c2410ts_init(void)函数中有
if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,"s3c2410_action", dev))
{
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
return -EIO;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,"s3c2410_action", dev))
{
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
iounmap(base_addr);
return -EIO;
}
(或者其他函数中,总之是这两句)
这两个函数就是注册中断的,可以看到IRQ_TS(触摸屏按下的中断)发生时,执行函数tylus_updown,IRQ_ADC(AD转换结束中断)发生时,则执行函stylus_action,那么就再来看这两个函数。
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) //判断触摸屏是否按下,若按下,则调用以下函数
{
touch_timer_fire(0);
}
return IRQ_HANDLED;
}
那么继续按步骤来,看touch_timer_fire。
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown)//判断是否按下
{
if (count != 0) //AD采集完成
{
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}//否则开始采集
xp = 0;
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);//启动AD转换
}
else //判断为抬起
{
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
}
}
从上面的函数中可以看出,第一次按下触摸屏后,count==0,则执行启动AD转换,这样就会发生AD转换结束中断,根据上面说的,将会调用
stylus_action,那么,没的说,继续!
static irqreturn_t stylus_action(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
count++;
if (count < (1<<2))//判断采集次数
{
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
}
else
{
mod_timer(&touch_timer, jiffies+1);
iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
}
return IRQ_HANDLED;
}
从上面的函数中可以看出,但AD转换不足4次(1<<2)则继续转换,当次数到了,那么一个时钟节拍后又调用touch_timer(mod_timer用法可Google一下
,也可看本网站网摘里的《内核定时器》篇,O(∩_∩)O哈哈~),那么在看……
static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);
看,又回来了……有去调用了touch_timer_fire!
那么,现在这个函数就要执行if (count != 0) 里面的程序了……做了什么呢??
哈哈,简单,算出平均的X方向与Y方向的AD转换值,然后通知内核,同步输入设备……
看到现在就应该有思路了,没错,定时器!
只要在触摸屏AD采集完同步输入设备后,点亮背光,同时注册定时器,当定时器到了,关联函数中执行关背光,O了!
至于背光控制就简单了……简单的LCD_POWEREN(GPG4)的高低电平……
当然了,前提是背光电路控制有这一功能!而且配置GPG4为输出……s3c2410_ts_connect中……
好了,给出我改后的……
static inline void s3c2410_ts_connect(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
////Add By Linan
s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_OUTP);
/////////
}
///////Add By Linan
static void My_fun(unsigned long data)
{
s3c2410_gpio_setpin(S3C2410_GPG4,0);
}
static struct timer_list lcd_timer=
TIMER_INITIALIZER(My_fun,0,0);
////////////////////////////
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown)//判断是否按下
{
if (count != 0) //AD采集完成
{
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
///////Add By Linan
s3c2410_gpio_setpin(S3C2410_GPG4,1);
mod_timer(&lcd_timer,jiffies+10*200);
////////////////////
}//否则开始采集
xp = 0;
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);//启动AD转换
}
else //判断为抬起
{
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
}
}
哈哈,简单的哇!好歹是分析了触摸屏驱动的源码了……定时器的使用……
好了,我改的地方加了注释的!
可是还是存在问题,就是触摸后屏是亮了,但是应用程序也在跑……本想按下后应用程序不响应的,可是,发现应用程序中点击一下,驱动中其实调用很多次……无奈了,看来驱动中没办法实现这一功能了……遗留问题,遗憾啊,希望有高手指点!