(1)vi s3c_ts.c
#include <linux/module.h>
#include <linux/irqreturn.h>
#include <linux/clk.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
struct s3c_ts_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
};
static volatile struct s3c_ts_regs *s3c_ts_regs;
static struct input_dev *s3c_ts_dev;
void enter_wait_pen_down_mode(void)
{
s3c_ts_regs->adctsc = 0xd3;
}
void enter_wait_pen_up_mode(void)
{
s3c_ts_regs->adctsc = 0x1d3;
}
static irqreturn_t pen_down_up_irq(int irq,void *dev_id)
{
if(s3c_ts_regs->adcdat0 & (1<<15))
{
printk("pen up\n");
enter_wait_pen_down_mode();
}
else
{
printk("pen down\n");
enter_wait_pen_up_mode();
}
return IRQ_HANDLED;
}
static int 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,1,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,IRQF_SAMPLE_RANDOM,"ts_pen",NULL);
enter_wait_pen_down_mode();
return 0;
}
static void s3c_ts_exit(void)
{
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");
测试驱动程序:
# insmod s3c_ts.ko
input: Unspecified device as /class/input/input0
pen down
pen up
# pen down
pen up
(2)vi s3c_ts.c(增加adc测量xy坐标)
static void enter_measure_xy_mode(void)
{
s3c_ts_regs->adctsc = (1<<3)|(1<<2);
}
static void start_adc(void)
{
s3c_ts_regs->adccon |= (1<<0);
}
static irqreturn_t adc_irq(int irq,void *dev_id)
{
static int cnt = 0;
printk("adc irq cnt = %d, x = %d, y = %d\n",++cnt,s3c_ts_regs->adcdat0 & 0x3ff,s3c_ts_regs->adcdat1 & 0x3ff);
enter_wait_pen_up_mode();
return IRQ_HANDLED;
}
static irqreturn_t pen_down_up_irq(int irq,void *dev_id)
{
if(s3c_ts_regs->adcdat0 & (1<<15))
{
printk("pen up\n");
enter_wait_pen_down_mode();
}
else
{
enter_measure_xy_mode();
start_adc();
}
return IRQ_HANDLED;
}
static int 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,1,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,IRQF_SAMPLE_RANDOM,"ts_pen",NULL);
request_irq(IRQ_ADC,adc_irq,IRQF_SAMPLE_RANDOM,"adc",NULL);
enter_wait_pen_down_mode();
return 0;
}
测试驱动程序:
# insmod s3c_ts.ko
input: Unspecified device as /class/input/input2
# adc irq cnt = 1, x = 97, y = 887
pen up
adc irq cnt = 2, x = 0, y = 969
pen up
adc irq cnt = 3, x = 57, y = 926
pen up
adc irq cnt = 4, x = 81, y = 906
pen up
(3)vi s3c_ts.c(优化测量xy坐标)
static int s3c_filter_ts(int x[],int y[])
{
#define ERR_LIMIT 10
int avg_x,avg_y;
int delta_x,delta_y;
avg_x = (x[0]+x[1])/2;
avg_y = (y[0]+y[1])/2;
delta_x = (x[2]>avg_x) ? (x[2]-avg_x) : (avg_x - x[2]);
delta_y = (y[2]>avg_y) ? (y[2]-avg_y) : (avg_y - y[2]);
if((delta_x > ERR_LIMIT)||(delta_y > ERR_LIMIT))
return 0;
avg_x = (x[1]+x[2])/2;
avg_y = (y[1]+y[2])/2;
delta_x = (x[3]>avg_x) ? (x[3]-avg_x) : (avg_x - x[3]);
delta_y = (y[3]>avg_y) ? (y[3]-avg_y) : (avg_y - y[3]);
if((delta_x > ERR_LIMIT)||(delta_y > ERR_LIMIT))
return 0;
return 1;
}
static irqreturn_t adc_irq(int irq,void *dev_id)
{
static int cnt = 0;
static int x[4],y[4];
int adcdat0,adcdat1;
adcdat0 = s3c_ts_regs->adcdat0;
adcdat1 = s3c_ts_regs->adcdat1;
if(s3c_ts_regs->adcdat0 & (1<<15))
{
cnt = 0;
enter_wait_pen_down_mode();
}
else
{
x[cnt] = adcdat0 & 0x3ff;
y[cnt] = adcdat1 & 0x3ff;
++cnt;
if(cnt==4)
{
if(s3c_filter_ts(x,y))
printk("x = %d, y = %d\n",(x[0]+x[1]+x[2]+x[3])/4,(y[0]+y[1]+y[2]+y[3])/4);
cnt = 0;
enter_wait_pen_up_mode();
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
static int 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,1,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,IRQF_SAMPLE_RANDOM,"ts_pen",NULL);
request_irq(IRQ_ADC,adc_irq,IRQF_SAMPLE_RANDOM,"adc",NULL);
s3c_ts_regs->adcdly = 0xffff;
enter_wait_pen_down_mode();
return 0;
}
测试驱动程序:
# insmod s3c_ts.ko
input: Unspecified device as /class/input/input5
pen up
# x = 621, y = 498
pen up
x = 647, y = 490
pen up
x = 654, y = 495
pen up
x = 654, y = 493
pen up
(4)vi s3c_ts.c(增加定时器支持长按和滑动)
static struct timer_list ts_timer;
static void s3c_ts_timer_function(unsigned long data)
{
if(s3c_ts_regs->adcdat0 & (1<<15))
{
enter_wait_pen_down_mode();
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
static irqreturn_t adc_irq(int irq,void *dev_id)
{
static int cnt = 0;
static int x[4],y[4];
int adcdat0,adcdat1;
adcdat0 = s3c_ts_regs->adcdat0;
adcdat1 = s3c_ts_regs->adcdat1;
if(s3c_ts_regs->adcdat0 & (1<<15))
{
cnt = 0;
enter_wait_pen_down_mode();
}
else
{
x[cnt] = adcdat0 & 0x3ff;
y[cnt] = adcdat1 & 0x3ff;
++cnt;
if(cnt==4)
{
if(s3c_filter_ts(x,y))
printk("x = %d, y = %d\n",(x[0]+x[1]+x[2]+x[3])/4,(y[0]+y[1]+y[2]+y[3])/4);
cnt = 0;
enter_wait_pen_up_mode();
mod_timer(&ts_timer,jiffies+HZ/100);
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
static int 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,1,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,IRQF_SAMPLE_RANDOM,"ts_pen",NULL);
request_irq(IRQ_ADC,adc_irq,IRQF_SAMPLE_RANDOM,"adc",NULL);
s3c_ts_regs->adcdly = 0xffff;
init_timer(&ts_timer);
ts_timer.function = s3c_ts_timer_function;
add_timer(&ts_timer);
enter_wait_pen_down_mode();
return 0;
}
static void s3c_ts_exit(void)
{
free_irq(IRQ_TC,NULL);
free_irq(IRQ_ADC,NULL);
iounmap(s3c_ts_regs);
input_unregister_device(s3c_ts_dev);
input_free_device(s3c_ts_dev);
del_timer(&ts_timer);
}
测试驱动程序:
# insmod s3c_ts.ko
input: Unspecified device as /class/input/input7
# x = 610, y = 385
x = 607, y = 384
x = 605, y = 384
x = 605, y = 383
x = 579, y = 393
pen up
x = 661, y = 375
x = 678, y = 388
x = 646, y = 383
x = 633, y = 382
x = 633, y = 375
pen up
(5)vi s3c_ts.c(输入子系统上报)
static irqreturn_t adc_irq(int irq,void *dev_id)
{
static int cnt = 0;
static int x[4],y[4];
int adcdat0,adcdat1;
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,ABS_PRESSURE,0);
input_report_key(s3c_ts_dev,BTN_TOUCH,0);
input_sync(s3c_ts_dev);
enter_wait_pen_down_mode();
}
else
{
x[cnt] = adcdat0 & 0x3ff;
y[cnt] = adcdat1 & 0x3ff;
++cnt;
if(cnt==4)
{
if(s3c_filter_ts(x,y)){
input_report_abs(s3c_ts_dev,ABS_X,(x[0]+x[1]+x[2]+x[3])/4);
input_report_abs(s3c_ts_dev,ABS_Y,(y[0]+y[1]+y[2]+y[3])/4);
input_report_abs(s3c_ts_dev,ABS_PRESSURE,1);
input_report_key(s3c_ts_dev,BTN_TOUCH,1);
input_sync(s3c_ts_dev);
}
cnt = 0;
enter_wait_pen_up_mode();
mod_timer(&ts_timer,jiffies+HZ/100);
}
else
{
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
测试驱动程序:
# ls /dev/event*
ls: /dev/event*: No such file or directory
# insmod s3c_ts.ko
input: Unspecified device as /class/input/input9
# ls /dev/event*
/dev/event0
# hexdump /dev/event0
0000000 1251 0000 2b3b 0004 0003 0000 021b 0000
0000010 1251 0000 2b50 0004 0003 0001 01a5 0000
0000020 1251 0000 2b54 0004 0003 0018 0001 0000
0000030 1251 0000 2b58 0004 0001 014a 0001 0000
0000040 1251 0000 2b5c 0004 0000 0000 0000 0000
使用tslib:(1)编译
tar xzf tslib-1.4.tar.gz
cd tslib
./autogen.sh
mkdir tmp
echo "ac_cv_func_malloc_0_nonnull=yes" > arm-linux.cache
./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
make
make install
cp ~/linux/nfs/tslib/tmp/* ~/workdir -rfd
# cd ~/workdir
# cp * / -rfd
(2)安装s3c_ts.ko,lcd.ko
************注意:
# insmod lcd.ko
Segmentation fault
。。。。重新编译lcd.c也不行。没办法,在uImage里使用自带的lcd驱动吧。
(3)vi /etc/ts.conf 使能module_raw input
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
ts_calibrate
运行./ts_calibrate程序,触摸屏矫正图标没有反应。网上所说的cat /dev/input/event0有乱码出现不能确定触摸屏驱动是没问题的,应该是驱动还是有问题。呵呵,先这样吧。