模塊加載後打印出水平和垂直方向的ad轉換結果,沒有做座標的轉換,只爲學習一下touch screen接口的編程方法,代碼記錄如下:
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
static struct input_dev *ts_dev; //定時器用於處理長按和滑動
static struct ts_regs_t{
unsigned long adccon;
unsigned long adctsc;
unsigned long adcdly;
unsigned long adcdat0;
unsigned long adcdat1;
unsigned long adcupdn;
};
static volatile struct ts_regs_t *ts_regs;
static volatile unsigned long *clkcon;
static struct clk *adc_clk;
static struct timer_list ts_timer;
void enable_adc_clock(void){
(*clkcon) |= (1<<15);
}
void enter_wait4down_mode(void){
ts_regs->adctsc = 0xd3; //等待中斷模式,檢測觸摸屏按下
}
void enter_wait4up_mode(void){
ts_regs->adctsc = 0x1d3; //等待中斷模式,檢測觸摸屏鬆開
}
//進入測量xy座標的工作模式
void enter_measure_xy_mode(void){
ts_regs->adctsc = (1<<3)|(1<<2);
}
//啓動ac轉換
void start_adc(void){
ts_regs->adccon |= (1<<0);
}
//adc中斷處理函數
static irqreturn_t grh_handle_adc_irq(int irq, void *dev_id){
static int adc_count = 0;
static int xv=0, yv=0;
if(ts_regs->adcdat0 & (1<<15)){
enter_wait4down_mode();
adc_count = 0;
xv = yv = 0;
}
else{ //多次取值取平均值
if(adc_count == 4){
printk(KERN_EMERG"count=%d x=%d y=%d\r", adc_count, xv>>2, yv>>2);
//上報事件
input_report_abs(ts_dev, ABS_X, xv>>2);
input_report_abs(ts_dev, ABS_Y, yv>>2);
input_report_abs(ts_dev, ABS_PRESSURE, 1);
input_report_key(ts_dev, BTN_TOUCH, 1);
input_sync(ts_dev);
adc_count = 0;
xv = yv = 0;
enter_wait4up_mode();
mod_timer(&ts_timer, jiffies+HZ/100); //10ms
}
else{
adc_count ++;
xv += (ts_regs->adcdat0)&0x3ff;
yv += (ts_regs->adcdat1)&0x3ff;
enter_measure_xy_mode();
start_adc();
}
}
return IRQ_HANDLED;
}
//tc中斷處理函數
static irqreturn_t grh_handle_tc_irq(int irq, void *dev_id){
if(ts_regs->adcdat0 & (1<<15)){
//printk(KERN_EMERG"pen up!\n");
enter_wait4down_mode();
}
else{
//printk(KERN_EMERG"pen down\n");
//enter_wait4up_mode();
enter_measure_xy_mode();
start_adc();
}
return IRQ_HANDLED;
}
//定時器超時處理函數
static void grh_handle_timer_int(unsigned long num){
if(ts_regs->adcdat0 & (1<<15)){
//上報事件
input_report_abs(ts_dev, ABS_PRESSURE, 0);
input_report_key(ts_dev, BTN_TOUCH, 0);
input_sync(ts_dev);
enter_wait4down_mode();
}
else{
enter_measure_xy_mode();
start_adc();
}
}
static int ts_init(void){
ts_dev = input_allocate_device();
//設置能夠產生哪些事件
set_bit(EV_KEY, ts_dev->evbit);
set_bit(EV_ABS, ts_dev->evbit);
set_bit(BTN_TOUCH, ts_dev->keybit); /*觸摸屏按鍵事件*/
input_set_abs_params(ts_dev, ABS_X, 0, 0x3ff, 0, 0); /*設置絕對位移取值範圍*/
input_set_abs_params(ts_dev, ABS_Y, 0, 0x3ff, 0, 0); /*設置絕對位移取值範圍*/
input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0); /*設置壓力的取值範圍,只有0和1*/
/*註冊*/
input_register_device(ts_dev);
//ioremap
ts_regs = ioremap(0x58000000, sizeof(struct ts_regs_t));
clkcon = ioremap(0x4C00000C, 4);
//使能時鐘,使得adc可以正常工作
adc_clk = clk_get(NULL, "adc");
if (!adc_clk) {
printk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clk);
/*
bit[14] PRESCEN=1 使能預分頻
bit[13:6] PRESCVL=49 預分頻數值爲49(pclk=50.625M) adcclk = 50.625M/50=1.0125MHz
bit[2] STDBM=0 不進入等待模式
bit[1] READ_START=0
bit[0] ENABLE_START=0
*/
ts_regs->adccon = (1<<14)|(49<<6);
ts_regs->adcdly = 0xffff; //設定延時,保證數據的準確性
//註冊中斷
if( request_irq(IRQ_TC, grh_handle_tc_irq, IRQF_SAMPLE_RANDOM, "irq_tc", ts_dev) ){
printk(KERN_EMERG"allocate IRQ_TC error!\n");
return -EIO;
}
if( request_irq(IRQ_ADC, grh_handle_adc_irq, IRQF_SHARED|IRQF_SAMPLE_RANDOM, "irq_adc", ts_dev) ){
printk(KERN_EMERG"allocate IRQ_ADC error!\n");
return -EIO;
}
init_timer(&ts_timer);
ts_timer.function = grh_handle_timer_int;
add_timer(&ts_timer);
enter_wait4down_mode();//等待中斷模式,檢測觸摸屏按下
return 0;
}
static void ts_exit(void){
iounmap(ts_regs);
iounmap(clkcon);
free_irq(IRQ_TC, ts_dev);
free_irq(IRQ_ADC, ts_dev);
input_unregister_device(ts_dev);
input_free_device(ts_dev);
del_timer(&ts_timer);
}
module_init(ts_init);
module_exit(ts_exit);
MODULE_AUTHOR("GRH");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("TOUCH SCREEN DRIVER");
MODULE_LICENSE("GPL");