linux 触摸结构体,S3C2440 Linux 触摸屏驱动

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

// YM_SEN输出驱动器使能,XP_SEN,YP_SEN输出驱动器禁止

// S3C2410_ADCTSC_XY_PST(3) -- 手动测量X、Y方向,等待中断模式

// x=0, 将ADCTSC[8]设置为0,即检测笔尖落下中断信号

#define WAIT4INT(x)  (((x)<<8) | \

S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \

S3C2410_ADCTSC_XY_PST(3))

/* ADCTSC Register Bits */

#define S3C2410_ADCTSC_YM_SEN       (1<<7)

#define S3C2410_ADCTSC_YP_SEN       (1<<6)

#define S3C2410_ADCTSC_XM_SEN       (1<<5)

#define S3C2410_ADCTSC_XP_SEN       (1<<4)

#define S3C2410_ADCTSC_PULL_UP_DISABLE  (1<<3)

#define S3C2410_ADCTSC_AUTO_PST     (1<<2)

#define S3C2410_ADCTSC_XY_PST(x)    (((x)&0x3)<<0)

/* ADCCON Register Bits */

#define S3C2410_ADCCON_ECFLG        (1<<15)

#define S3C2410_ADCCON_PRSCEN       (1<<14)

#define S3C2410_ADCCON_PRSCVL(x)    (((x)&0xFF)<<6)

#define S3C2410_ADCCON_PRSCVLMASK   (0xFF<<6)

#define S3C2410_ADCCON_SELMUX(x)    (((x)&0x7)<<3)

#define S3C2410_ADCCON_MUXMASK      (0x7<<3)

#define S3C2410_ADCCON_STDBM        (1<<2)

#define S3C2410_ADCCON_READ_START   (1<<1)

#define S3C2410_ADCCON_ENABLE_START (1<<0)

#define S3C2410_ADCCON_STARTMASK    (0x3<<0)

#ifdef S3C2410_ADCCON

#undef S3C2410_ADCCON

#endif

#ifdef S3C2410_ADCTSC

#undef S3C2410_ADCTSC

#endif

#ifdef S3C2410_ADCDLY

#undef S3C2410_ADCDLY

#endif

#ifdef S3C2410_ADCDAT0

#undef S3C2410_ADCDAT0

#endif

#ifdef S3C2410_ADCDAT1

#undef S3C2410_ADCDAT1

#endif

#ifdef S3C2410_PA_ADC

#undef S3C2410_PA_ADC

#endif

#define S3C2410_PA_ADC     (0x58000000)

staticvoid__iomem *base_addr;

#define S3C2410_ADCCON (base_addr+(0x00))

#define S3C2410_ADCTSC (base_addr+(0x04))

#define S3C2410_ADCDLY (base_addr+(0x08))

#define S3C2410_ADCDAT0 (base_addr+(0x0c))

#define S3C2410_ADCDAT1 (base_addr+(0x10))

#ifdef CONFIG_PM

#include 

#endif

// 支持拖拽

// 若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应。

// 可以看到read接口被调用到,不知为何图标没有响应。

#define HOOK_FOR_DRAG

//#define   DEBUG

#ifdef DEBUG

#define DPRINTK printk

#else

#define DPRINTK

#endif

typedefstruct{

unsignedshortpressure;

unsignedshortx;

unsignedshorty;

unsignedshortpad;

} TS_RET;

typedefstruct{

intxscale;

intxtrans;

intyscale;

intytrans;

intxyswap;

} TS_CAL;

#define PEN_UP          0

#define PEN_DOWN    1

#define PEN_FLEETING    2

#define MAX_TS_BUF  16  /* how many do we want to buffer */

#undef USE_ASYNC

#define DEVICE_NAME "s3c2410-ts"

#define TSRAW_MINOR 1

typedefstruct{

unsignedintpenStatus;/* PEN_UP, PEN_DOWN, PEN_SAMPLE */

TS_RET buf[MAX_TS_BUF];/* protect against overrun */

unsignedinthead, tail;/* head and tail for queued events */

wait_queue_head_t wq;

spinlock_t lock;

#ifdef USE_ASYNC

structfasync_struct *aq;

#endif

#ifdef CONFIG_PM

structpm_dev *pm_dev;

#endif

} TS_DEV;

staticTS_DEV tsdev;

#define BUF_HEAD    (tsdev.buf[tsdev.head])

#define BUF_TAIL    (tsdev.buf[tsdev.tail])

#define INCBUF(x,mod)   ((++(x)) & ((mod) - 1))

staticinttsMajor = 0;

staticvoid(*tsEvent)(void);

#ifdef HOOK_FOR_DRAG

#define TS_TIMER_DELAY  (HZ/100) /* 10 ms */

staticstructtimer_list ts_timer;

#endif

// pick-up regs val from 2.4.18&2440

// YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖落下中断信号,等待中断模式

#define wait_down_int() __raw_writel(0x000000d3,S3C2410_ADCTSC)

// YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖抬起中断信号,等待中断模式

#define wait_up_int()   __raw_writel(0x000001d3, S3C2410_ADCTSC)

// XM_SEN、XP_SEN输出驱动器使能,XP上拉禁止,正常ADC转换,X方向测量模式

#define mode_x_axis()   __raw_writel(0x00000069, S3C2410_ADCTSC)

// 相当于__raw_writel(0x00000068, S3C2410_ADCTSC),即

// XM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,无操作模式

#define mode_x_axis_n() __raw_writel(XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \

XP_PULL_UP_DIS | XP_PST(NOP_MODE), S3C2410_ADCTSC)

// YM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,Y方向测量模式

#define mode_y_axis()   __raw_writel(0x0000009a, S3C2410_ADCTSC)

// __raw_writel(0x00007ffa, S3C2410_ADCCON); -- A/D转换器预分频器使能,预分频值0xff,模拟输入通道SEL_MUX为XP,正常工作模式,使能读启动操作

// __raw_readl(S3C2410_ADCDAT0); -- 读取ADCDAT)的值

#define start_adc_x()   do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \

__raw_readl(S3C2410_ADCDAT0); }while(0)

// 怎么跟start_adc_x()配置一样?应该为0x00007fea?

#define start_adc_y()   do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \

__raw_readl(S3C2410_ADCDAT1); }while(0)

// 禁止读启动操作,即READ_START位置0

#define disable_ts_adc()    __raw_writel(__raw_readl(S3C2410_ADCCON)&0xfffffffd, S3C2410_ADCCON)

staticintadc_state = 0;

staticintx, y;/* touch screen coorinates */

#ifdef HOOK_FOR_DRAG

#define RT_BT_EMU_TM    ((HZ>>1)+(HZ>>2))   //0.75S

//static u16 ts_r_x[5];

//static u16 ts_r_y[5];

//static u16 ts_r_idx;

//static u16 ts_r_beg;

staticu32 dn_start;

#endif

staticvoidtsEvent_raw(void)

{

DPRINTK("@@@@@@@@ tvEvent_raw() @@@@@@@@@\n");

if(tsdev.penStatus == PEN_DOWN)

{

//u16 i, j;

#ifdef HOOK_FOR_DRAG

ts_timer.expires = jiffies + TS_TIMER_DELAY;

add_timer(&ts_timer);

#endif

BUF_HEAD.x = x;

BUF_HEAD.y = y;

#ifdef HOOK_FOR_DRAG

BUF_HEAD.pressure = ((jiffies - dn_start) >= RT_BT_EMU_TM) ? PEN_FLEETING : PEN_DOWN;

#else

BUF_HEAD.pressure = PEN_DOWN;

#endif

}/* if (tsdev.penStatus == PEN_DOWN) */

else

{

#ifdef HOOK_FOR_DRAG

del_timer(&ts_timer);

#endif

BUF_HEAD.x = x;

BUF_HEAD.y = y;

BUF_HEAD.pressure = PEN_UP;

}

tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);

DPRINTK("@@@@@@@@ wake_up_interruptible() in tvEvent_raw() @@@@@@@@@\n");

wake_up_interruptible(&(tsdev.wq));

#ifdef USE_ASYNC

if(tsdev.aq)

kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);

#endif

#ifdef CONFIG_PM

pm_access(tsdev.pm_dev);

#endif

}

staticinttsRead(TS_RET * ts_ret)

{

spin_lock_irq(&(tsdev.lock));

ts_ret->x = BUF_TAIL.x;

ts_ret->y = BUF_TAIL.y;

ts_ret->pressure = BUF_TAIL.pressure;

tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);

spin_unlock_irq(&(tsdev.lock));

returnsizeof(TS_RET);

}

staticssize_t s3c2410_ts_read(structfile *filp,char*buffer,size_tcount, loff_t *ppos)

{

TS_RET ts_ret;

retry:

if(tsdev.head != tsdev.tail)

{

intcount;

count = tsRead(&ts_ret);

if(count)

{

printk("@@@@@ ts_ret.x: %hd, ts_ret.y: %hd @@@@@@@\n", ts_ret.x, ts_ret.y);

copy_to_user(buffer, (char*)&ts_ret, count);

}

returncount;

}

else

{

if(filp->f_flags & O_NONBLOCK)

return-EAGAIN;

interruptible_sleep_on(&(tsdev.wq));

if(signal_pending(current))

return-ERESTARTSYS;

gotoretry;

}

returnsizeof(TS_RET);

}

#ifdef USE_ASYNC

staticints3c2410_ts_fasync(intfd,structfile *filp,intmode)

{

returnfasync_helper(fd, filp, mode, &(tsdev.aq));

}

#endif

staticunsignedints3c2410_ts_poll(structfile *filp,structpoll_table_struct *wait)

{

poll_wait(filp, &(tsdev.wq), wait);

return(tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);

}

staticinlinevoidstart_ts_adc(void)

{

adc_state = 0;

mode_x_axis();

start_adc_x();

}

staticinlinevoids3c2410_get_XY(void)

{

if(adc_state == 0)

{

adc_state = 1;

disable_ts_adc();

y = __raw_readl(S3C2410_ADCDAT1) & 0x3ff;//x:f04 y:f0e dh  by pht.

mode_y_axis();

start_adc_y();

}

elseif(adc_state == 1)

{

adc_state = 0;

disable_ts_adc();

x = __raw_readl(S3C2410_ADCDAT0) & 0x3ff;//y:f04 x:f0e dh by pht.

printk("@@@@@@ PEN DOWN: x: %d, y: %d @@@@@@\n", x, y);

wait_up_int();

tsdev.penStatus = PEN_DOWN;

tsEvent();

}

}

staticirqreturn_t s3c2410_isr_adc(intirq,void*dev_id,structpt_regs *reg)

{

DPRINTK("@@@@@@@@ s3c2410_isr_adc() @@@@@@@@\n");

spin_lock_irq(&(tsdev.lock));

if(tsdev.penStatus == PEN_UP)

{

DPRINTK("@@@@@@ s3c2410_isr_adc 1 @@@@@@\n");

s3c2410_get_XY();

}

#ifdef HOOK_FOR_DRAG

else

{

DPRINTK("@@@@@@ s3c2410_isr_adc 2 @@@@@@\n");

s3c2410_get_XY();

}

#endif

spin_unlock_irq(&(tsdev.lock));

returnIRQ_HANDLED;

}

staticirqreturn_t s3c2410_isr_tc(intirq,void*dev_id,structpt_regs *reg)

{

DPRINTK("@@@@@@@@ s3c2410_isr_tc() @@@@@@@@\n");

spin_lock_irq(&(tsdev.lock));

if(tsdev.penStatus == PEN_UP)

{

DPRINTK("@@@@@@@@ s3c2410_isr_tc 1 @@@@@@@@\n");

#ifdef HOOK_FOR_DRAG

dn_start = jiffies;// add by gzliu

#endif

start_ts_adc();

}

else

{

tsdev.penStatus = PEN_UP;

DPRINTK("@@@@@@@@ s3c2410_isr_tc 2 @@@@@@@@\n");

printk("@@@@@@@ PEN UP: x: %d, y: %d @@@@@@@\n", x, y);

wait_down_int();

tsEvent();

}

spin_unlock_irq(&(tsdev.lock));

returnIRQ_HANDLED;

}

#ifdef HOOK_FOR_DRAG

staticvoidts_timer_handler(unsignedlongdata)

{

spin_lock_irq(&(tsdev.lock));

if(tsdev.penStatus == PEN_DOWN)

{

start_ts_adc();

}

spin_unlock_irq(&(tsdev.lock));

}

#endif

staticints3c2410_ts_open(structinode *inode,structfile *filp)

{

tsdev.head = tsdev.tail = 0;

tsdev.penStatus = PEN_UP;

#ifdef HOOK_FOR_DRAG

init_timer(&ts_timer);

ts_timer.function = ts_timer_handler;

#endif

tsEvent = tsEvent_raw;

init_waitqueue_head(&(tsdev.wq));

//MOD_INC_USE_COUNT;

return0;

}

staticints3c2410_ts_release(structinode *inode,structfile *filp)

{

#ifdef HOOK_FOR_DRAG

del_timer(&ts_timer);

#endif

//MOD_DEC_USE_COUNT;

return0;

}

staticstructfile_operations s3c2410_fops = {

owner:  THIS_MODULE,

open:   s3c2410_ts_open,

read:   s3c2410_ts_read,

release:    s3c2410_ts_release,

#ifdef USE_ASYNC

fasync: s3c2410_ts_fasync,

#endif

poll:   s3c2410_ts_poll,

};

voidtsEvent_dummy(void) {}

#ifdef CONFIG_PM

staticints3c2410_ts_pm_callback(structpm_dev *pm_dev, pm_request_t req,

void*data)

{

switch(req) {

casePM_SUSPEND:

tsEvent = tsEvent_dummy;

break;

casePM_RESUME:

tsEvent = tsEvent_raw;

wait_down_int();

break;

}

return0;

}

#endif

staticstructclk   *adc_clock;

staticint__init s3c2410ts_probe(structdevice *dev)

{

intret;

tsEvent = tsEvent_dummy;

DPRINTK("@@@@@@@@@@ s3c2410ts_probe @@@@@@@@@@\n");

ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);

if(ret 

printk(DEVICE_NAME" can't get major number\n");

returnret;

}

tsMajor = ret;

adc_clock = clk_get(NULL,"adc");

if(!adc_clock) {

printk(KERN_ERR"failed to get adc clock source\n");

return-ENOENT;

}

clk_use(adc_clock);

clk_enable(adc_clock);

base_addr = ioremap(S3C2410_PA_ADC, 0x20);

__raw_writel(WAIT4INT(0), S3C2410_ADCTSC);

__raw_writel(30000, S3C2410_ADCDLY);// 30000--20000

ret = request_irq(IRQ_ADC, s3c2410_isr_adc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_adc);

if(ret)

gotoadc_failed;

ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_tc);

if(ret)

gototc_failed;

/* Wait for touch screen interrupts */

wait_down_int();

#ifdef CONFIG_DEVFS_FS

devfs_mk_dir("touchscreen");

devfs_mk_cdev(MKDEV(tsMajor, TSRAW_MINOR), S_IFCHR|S_IRUGO|S_IWUSR,"touchscreen/%s","0raw");

#endif

#ifdef CONFIG_PM

tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT, s3c2410_ts_pm_callback);

#endif

return0;

tc_failed:

{

printk(KERN_ERR"tc failed!!!!!!!!!!!!!\n");

free_irq(IRQ_ADC, s3c2410_isr_adc);

}

adc_failed:

{

printk(KERN_ERR"adc failed!!!!!!!!!!!!!\n");

returnret;

}

}

staticstructdevice_driver s3c2410ts_driver = {

.name       = DEVICE_NAME,

.bus        = &platform_bus_type,

.probe      = s3c2410ts_probe,

#ifdef CONFIG_PM

.suspend    = s3c2410ts_suspend,

.resume     = s3c2410ts_resume,

#endif

};

staticint__init s3c2410ts_init(void)

{

intret;

printk("@@@@@@@@ s3c2410ts init() @@@@@@@\n");

ret = driver_register(&s3c2410ts_driver);

if(ret)

{

printk("register %s driver failed, return code is %d\n", DEVICE_NAME, ret);

}

else

{

printk("@@@@@@@ register %s driver success, return code is %d @@@@@@@@@@\n", DEVICE_NAME, ret);

}

returnret;

}

staticvoid__exit s3c2410ts_exit(void)

{

#ifdef CONFIG_DEVFS_FS

devfs_remove("touchscreen/%d", 0);

devfs_remove("touchscreen");

#endif

unregister_chrdev(tsMajor, DEVICE_NAME);

#ifdef CONFIG_PM

pm_unregister(tsdev.pm_dev);

#endif

free_irq(IRQ_ADC, s3c2410_isr_adc);

free_irq(IRQ_TC, s3c2410_isr_tc);

driver_unregister(&s3c2410ts_driver);

}

module_init(s3c2410ts_init);

module_exit(s3c2410ts_exit);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值