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
上一篇:OK6410分層分離(總線-驅動-設備模型)
下一篇:OK6410之LCD驅動
推薦閱讀
史海拾趣
Elektron公司的故事始于1942年,由威利·科伯以Elektron物理技術設備工廠Kerber的名稱成立。當時,該公司主要生產基于汞蒸氣整流器的固定電池電源和船用電池充電器。這些產品在市場上取得了良好的反響,為公司的發展奠定了堅實的基礎。在隨后的幾年里,Elektron不斷擴大產品范圍,開始涉足汽車行業的電池充電器以及焊接和切割工藝的電源等領域。
隨著公司的發展,浙江東亞電子不斷拓展其產業布局。除了傳統的電力電子元件、分流器等產品外,公司還涉足新能源汽車、充電樁、變頻器和儲能等領域。特別是在新能源汽車和充電樁領域,公司緊跟國家“新基建”發展戰略,推出了一系列具有競爭力的產品,為公司帶來了新的增長點。
成立于2004年的珠海艾派克微電子有限公司,在創業初期便致力于集成電路芯片設計領域的探索。公司憑借著對CPU設計技術、多核SoC專用芯片設計技術、安全芯片設計技術等核心技術的深入研究,逐步在行業內積累了良好的口碑。這一時期,艾派克堅持以市場需求為導向,不斷優化產品性能,為公司的長遠發展奠定了堅實的基礎。
成立于2004年的珠海艾派克微電子有限公司,在創業初期便致力于集成電路芯片設計領域的探索。公司憑借著對CPU設計技術、多核SoC專用芯片設計技術、安全芯片設計技術等核心技術的深入研究,逐步在行業內積累了良好的口碑。這一時期,艾派克堅持以市場需求為導向,不斷優化產品性能,為公司的長遠發展奠定了堅實的基礎。
隨著市場需求的多樣化,美高測開始提供更加定制化的高壓半導體測試解決方案。公司深入了解客戶的具體需求,從產品設計到售后服務,全程參與并提供專業指導。例如,針對某些特定行業的高壓電纜測試需求,美高測設計并生產了具有超長測試距離和高精度測試結果的專用設備,贏得了包括軍工、航空航天在內的多個高端客戶的青睞。
上世紀60、70年代,韓國經濟蓬勃發展,工業自動化需求迅速增長,但傳感器與控制儀表的國內市場仍是一片空白。Autonics的創始人看到了這個巨大的市場機會,于1977年創立了Autonics公司。公司初創時期,面臨著資金短缺、技術落后等諸多挑戰,但創始人憑借著對技術的執著追求和對市場的敏銳洞察,帶領公司逐步走上正軌。
Agilent Fundamentals of RF and Microwave Modern receiving systems must often process veryweak signals, but the noise added by the systemcomponents tends to obscure those very weak signals.Sensitivity, bit error ratio (BER) and noise figure aresystem parameters that chara ...… 查看全部問答∨ |
長期供應頻譜分析儀HP8563E/E4402B/E4403B/MS2665C/MS 一、 綜合測試儀 R&S CMU200(可測GSM900/1800);Agilent8960 E5515B(可測GSM900/1800/1900/GPRS);Agilnet8960 E5515C(OPT:002、003,可測GSM、CDMA);R&S CMD55(可測900/1800);R&S CMD60(DECT測試儀);MT8801B(PHS測試儀); ...… 查看全部問答∨ |
我現在在對話框中添加了按鈕 void xxxDlg::OnButton1() 想實現的功能有兩個,點擊按鈕后首先能獲取要顯示圖片的路徑,現在已經實現了并把路徑保存在CString pathname 中。第二個功能 想接著把對應路徑的這個圖片顯示到對話框中。(這個按鈕是程序 ...… 查看全部問答∨ |
|
尋有無線條碼數據終端Symbol PDT8146編程經驗的高手 想做一個固定資產清查軟件: 通過無線終端可以實現對粘有條碼的設備進行清查,并能夠與服務器數據進行互連 PC端的程序不需要實現,只要實現無線終端查詢和報表功能.請有興趣的朋友與我聯系,有償服務 QQ 30107562 暗號 無線終端… 查看全部問答∨ |
|
在使用ADS Debug uC/OS系統和一個簡單的讓蜂鳴器響的應用程序時,AXD loading image后,沒有進入StartUP函數而是進入Disassembly,Go后不停的running image ,蜂鳴器不響,也不知道是不是下到板子里了。 請問是怎么回事?… 查看全部問答∨ |
|
論壇活動難免會出現某些網友為了拿獎品注冊多個賬號來參與活動! 以往這種情況會比較少,但是本次TI 教室培訓搶樓活動有些網友明顯為了拿獎品而來。我今天實在有點不能忍受,跟大家抱怨一下。 也希望不要再出現這種情況。 網友姓名我就不說錯來 ...… 查看全部問答∨ |