ts.c源码:
#include "linux/module.h"
#include "linux/init.h"
#include "linux/fs.h"
#include "linux/interrupt.h"
#include "linux/irq.h"
#include "linux/sched.h"
#include "linux/pm.h"
#include "linux/sysctl.h"
#include "linux/proc_fs.h"
#include "linux/delay.h"
#include "linux/platform_device.h"
#include "linux/input.h"
#include "linux/io.h"
#include "linux/clk.h"
#include "linux/delay.h"
static struct timer_list ts_timer;
static struct input_dev *ts_dev;
struct adc_regs {
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
unsigned long adcclrint;
unsigned long reserved;
unsigned long adcclrintpndnup;
};
static struct adc_regs *adc_regs;
static void enter_wait_for_pen_down(void)
{
adc_regs->adctsc = 0xd3;
}
static void enter_wait_for_pen_up(void)
{
adc_regs->adctsc = 0x1d3;
}
static void enter_measure_xy_mode(void)
{
adc_regs->adctsc = ((1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2));
}
static void start_adc(void)
{
adc_regs->adccon |= (1<<0);
}
static irqreturn_t ts_pen_down_up_isr(int irq, void *dev_id)
{
unsigned long data0, data1;
int down;
data0 = adc_regs->adcdat0;
data1 = adc_regs->adcdat1;
down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));
if (!down)
{
//printk("pen up\n");
enter_wait_for_pen_down();
// 调用evdev_event: 保存,唤醒
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(ts_dev);
}
else
{
//printk("pen down\n");
//enter_wait_for_pen_up();
// 进入"自动测量x/y座标模式"
enter_measure_xy_mode();
// 启动ADC
start_adc();
}
adc_regs->adcupdn = 0;
adc_regs->adcclrint = 0;
adc_regs->adcclrintpndnup = 0;
return IRQ_HANDLED;
}
static irqreturn_t adc_isr(int irq, void *dev_id)
{
// 为何不在这里立刻处理ADC到结果?
// 因为6410的ADC有个缺点:
// 当ADC刚完成时, 必须等待若干ms,
// 才能读取adcdat0,adcdata1来判断
// 当前的触摸屏是被按下还是松开
// 启动定时器, 是为了不在中断处理函数里等待
mod_timer(&ts_timer, jiffies + HZ/100);
enter_wait_for_pen_up();
adc_regs->adcupdn = 0;
adc_regs->adcclrint = 0;
adc_regs->adcclrintpndnup = 0;
return IRQ_HANDLED;
}
static irqreturn_t adc_isr_ok_old(int irq, void *dev_id)
{
int x,y;
int adcdat0,adcdat1;
int down;
#if 1 // in auto xy mode, after adc interrupt, have to wait several ms to test up/down
udelay(1000);
udelay(1000);
udelay(1000);
udelay(1000);
#endif
adcdat0 = adc_regs->adcdat0;
adcdat1 = adc_regs->adcdat1;
x = adcdat0 & 0xfff;
y = adcdat1 & 0xfff;
down = (!(adcdat0 & (1<<15))) && (!(adcdat1 & (1<<15)));
//printk("adcdat0 = 0x%x, adc_dat1 = 0x%x\n", adcdat0, adcdat1);
if (down)
{
//printk("enter_wait_for_pen_up\n");
enter_wait_for_pen_up();
//printk("x = %d, y = %d\n", x, y);
input_event(ts_dev, EV_ABS, ABS_X, x);
input_event(ts_dev, EV_ABS, ABS_Y, y);
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(ts_dev);
// 启动定时器
mod_timer(&ts_timer, jiffies + HZ/100);
}
else
{
//printk("enter_wait_for_pen_down\n");
enter_wait_for_pen_down();
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(ts_dev);
}
adc_regs->adcupdn = 0;
adc_regs->adcclrint = 0;
adc_regs->adcclrintpndnup = 0;
return IRQ_HANDLED;
}
static void ts_timer_function_ok_old(unsigned long data)
{
// 如果触摸笔已经松开, 就没必要再次启动ADC
// 否则, 启动ADC
unsigned long data0, data1;
int down;
data0 = adc_regs->adcdat0;
data1 = adc_regs->adcdat1;
down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));
if (down)
{
enter_measure_xy_mode();
start_adc();
}
else
{
enter_wait_for_pen_down();
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(ts_dev);
}
}
static void ts_timer_function(unsigned long data)
{
// 如果触摸笔已经松开, 就没必要再次启动ADC
// 否则, 启动ADC
unsigned long data0, data1;
int down;
int x, y;
data0 = adc_regs->adcdat0;
data1 = adc_regs->adcdat1;
down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));
if (down)
{
x = data0 & 0xfff;
y = data1 & 0xfff;
input_event(ts_dev, EV_ABS, ABS_X, x);
input_event(ts_dev, EV_ABS, ABS_Y, y);
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);
input_sync(ts_dev);
enter_measure_xy_mode();
start_adc();
}
else
{
enter_wait_for_pen_down();
input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);
input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);
input_sync(ts_dev);
}
}
static int ts_init(void)
{
struct clk *clk;
// 1. 分配input_dev
ts_dev = input_allocate_device();
// 2. 设置
// 2.1 能产生哪类事件
set_bit(EV_KEY, ts_dev->evbit);
set_bit(EV_ABS, ts_dev->evbit);
// 2.2 能产生这类事件里的哪些事件
set_bit(BTN_TOUCH, ts_dev->keybit);
input_set_abs_params(ts_dev, ABS_X, 0, 0xfff, 0, 0);
input_set_abs_params(ts_dev, ABS_Y, 0, 0xfff, 0, 0);
input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
// 3. 注册
input_register_device(ts_dev);
// 4. 硬件相关
adc_regs = ioremap(0x7E00B000, sizeof(struct adc_regs));
clk = clk_get(NULL, "adc");
clk_enable(clk); // PCLK_GATE[12]设为1
// bit[16] : 1 = 12-bit A/D conversion
// bit[14] : 1 - enable A/D converter prescaler enable
// bit[13:6] : A/D converter prescaler value,
// PCLK=66500000, adcclk=pclk/(n+1)
// 取值13, adclk=66.5MHz/14=4.75
adc_regs->adccon = (1<<16) | (1<<14) | (65<<6);
adc_regs->adcdly = 0xffff;
adc_regs->adcclrintpndnup = 0;
request_irq(IRQ_TC, ts_pen_down_up_isr, IRQF_SHARED, "pen_down_up", 1);
request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc", 1);
init_timer(&ts_timer);
ts_timer.expires = 0;
ts_timer.function = ts_timer_function;
add_timer(&ts_timer);
// 进入"wait for interrupt mode", 等待触摸笔按下或松开的模式
enter_wait_for_pen_down();
return 0;
}
static void ts_exit(void)
{
del_timer(&ts_timer);
free_irq(IRQ_TC, 1);
free_irq(IRQ_ADC, 1);
iounmap(adc_regs);
input_unregister_device(ts_dev);
input_free_device(ts_dev);
}
module_init(ts_init);
module_exit(ts_exit);
MODULE_LICENSE("GPL");
====================================================================
Mekefile文件:
KERN_DIR = /home/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += ts.o
=====================================================================
测试:
一、配置内核make menuconfig ARCH=arm 去掉第三张图片中touchscreens选项前的*
若只做这一步,编译内核会提示如下错误:
arch/arm/mach-s3c64xx/built-in.o: In function `smdk6410_machine_init':
/xh/work/linux-3.0.1/arch/arm/mach-s3c64xx/mach-smdk6410.c:1096: undefined reference to `s3c_ts_set_platdata'
arch/arm/mach-s3c64xx/built-in.o:(.init.data+0x26c): undefined reference to `s3c_device_ts'
make: *** [.tmp_vmlinux1] Error 1
[root@IVAN linux-3.0.1]#
二、打开/arch/arm/mach-s3c64xx/mach-smdk6410.c
搜索 “s3c_ts_set_platdata”和“s3c_device_ts”,并注释掉这两行。
成功……
三、使用新内核启动:
1、编译内核:
make zImage //生成内核镜像文件
cp arch/arm/boot/zImage ../../zImage_no_ts
2、把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;
3、用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:
tftp 50008000 zImage_no_ts
nand erase 200000 500000
nand write 50008000 200000 500000
4、烧写完成后设置开发版为nand flash启动,使用新内核启动。
四、编译测试(详细可以参考JZ2440触摸屏驱动程序(输入子系统)):
insmod ts.ko
insmod lcd.ko
编译:
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
set bootargs root=/dev/nfs nfsroot=10.1.0.124:/rootfs ip=10.1.0.126 console=ttySAC0
安装:
cd tmp
cp * -rf 开发板的/
使用:
1.
修改 /etc/ts.conf第1行(去掉#号):
# module_raw input
改为:
module_raw input
2.
export TSLIB_FBDEVICE=/dev/fb0 # LCD
export TSLIB_TSDEVICE=/dev/event2 # 触摸屏
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
测试:
ts_calibrate
ts_test
hexdump /dev/event2
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』