linux 触摸屏驱动模块,linux下s3c2440的触摸屏驱动

//ts.c

#include "ypublic.h"                    //import the public header file

#define YDRIVER_NAME "TS_TEST"     //device name

#define YMAJOR 100                //device major

MODULE_LICENSE("Dual BSD/GPL");    //license

void adc_task(ulong p);            //adc sub irq routine

DECLARE_TASKLET(_adc_task,adc_task,0);    //the tasklet for adc irq

#define ST_ADC_TEST 1            //a state for test stylus is up or down

#define ST_ADC_AUTOXY 2            //a state for measure x and y position

typedef struct _t_adc_dev{            //my device strtuct

//struct cdev dev;            //my device,if you want add open\close...,need initialize this member

t_adcregs_p padcreg;            //adc is register pointer

t_clockreg_p pclkreg;            //clock and power are register pointer

struct timer_list timer;            //timer

uint counter;                    //counter

t_fifo fifo;                    //an FIFO buffer

uint x;                        //current     X

uint y;                        //current     y

uint adc_state;                //adc state

}t_adc_dev;

t_adc_dev *_padcdev;                //a global device pointer

void adc_task(ulong p)                //adc sub irq routine

{

uint x,y;

x=fifo_pop(&_padcdev->fifo);        //get x from FIFO buffer

y=fifo_pop(&_padcdev->fifo);        //get y from FIFO buffer

if(abs(_padcdev->x-x)>5||abs(_padcdev->y-y)>5)    //

{

if(_padcdev->x==0xfff)        //first pointer whit stylus down

printk(KERN_INFO"have stylus down\n");

_padcdev->x=x;            //update current x

_padcdev->y=y;            //update current y

printk(KERN_INFO"%u : ( %u , %u )\n",

_padcdev->counter++,x,y);

}

_padcdev->timer.data=1;            //timer for measure x and y position

_padcdev->timer.expires=MS(10);    //delay 10 ms

add_timer(&_padcdev->timer);    //add timer

}

irqreturn_t on_adc(int irq,void *id)    //adc irq routine

{

uint x,y;

if(_padcdev->adc_state==ST_ADC_AUTOXY)    //for measure x and y position

{

x=_padcdev->padcreg->ADCDAT0&0x3ff;    //get X

y=_padcdev->padcreg->ADCDAT1&0x3ff;    //get Y

if(x!=0&&y!=0)                            //stylus was down or not

{                                    //stylus was down

fifo_push(&_padcdev->fifo,x);            //push X value to FIFO buffer

fifo_push(&_padcdev->fifo,y);            //push Y value to FIFO buffer

_padcdev->timer.data=2;                //timer for test stylus was down or not

_padcdev->timer.expires=MS(1);        //delay 1 ms

add_timer(&_padcdev->timer);        //add timer

}

else{                                    //stylus isn't down

if(_padcdev->x!=0xfff)                //stylus was up or not

printk(KERN_INFO"stylus up\n");

_padcdev->padcreg->ADCTSC=0xd3;    //Waiting for Interrupt Mode

enable_irq(IRQ_TC);                //enable touch screen interrupt

}

}

else if(_padcdev->adc_state==ST_ADC_TEST)    //for test stylus is up or down

{

if((_padcdev->padcreg->ADCDAT0&0x3ff)<1000)

{                                    //stylus was not down

fifo_flush(&_padcdev->fifo,2);            //clear the dataes of pushed on current

if(_padcdev->x!=0xfff)                //stylus was up

printk(KERN_INFO"stylus up\n");

_padcdev->padcreg->ADCTSC=0xd3;    //Waiting for Interrupt Mode

enable_irq(IRQ_TC);                //enable touch screen interrupt

}

else

{

tasklet_schedule(&_adc_task);            //run sub irq routine on free time

}

}

return IRQ_HANDLED;

}

irqreturn_t on_tc(int irq,void* id)

{

disable_irq_nosync(irq);                //disable touch screen interrupt

_padcdev->y=0xfff;                    //initialize X andY for a impossible value

_padcdev->x=_padcdev->y;            //X and Y region was (0-0x3ff)

_padcdev->padcreg->ADCTSC&=0xffc;    //clear INT_TC bit by change the mode to no operation mode

_padcdev->timer.data=1;                //timer for measure x and y position

_padcdev->timer.expires=MS(25);        //delay 25 ms

add_timer(&_padcdev->timer);        //add timer

return IRQ_HANDLED;                //irq return

}

void on_timer(ulong d)

{

switch(d){

case 1:

{

_padcdev->padcreg->ADCTSC=0x90|SETB(3)|SETB(2);    // XP pull-up disable and auto sequential measurement of X-position, Y-position

_padcdev->padcreg->ADCCON|=0x1;                //adc conversion start

_padcdev->adc_state=ST_ADC_AUTOXY;            //adc conversion for measure x and y

break;

}

case 2:

{

_padcdev->adc_state=ST_ADC_TEST;                //adc conversion for test stylus was down or not

_padcdev->padcreg->ADCTSC=SETB(4);                //YP output heigh level,XP was used as analog input, and no operation mode

_padcdev->padcreg->ADCCON|=setNB(7,_padcdev->padcreg->ADCCON,3,5)|0x1;//start adc conversion from XP

break;

}

}

}

int __init init_adc(void)

{

int rs=0;                                    //result

dev_t dev=MKDEV(YMAJOR,0);                //device ID

_padcdev=kmalloc(sizeof(t_adc_dev),GFP_KERNEL);//malloc space for device

if(_padcdev==NULL)

{

rs=-ENOMEM;                            //no memery

goto fail1;

}

fifo_init(&_padcdev->fifo);                    //initialize FIFO buffer struct

_padcdev->pclkreg=(t_clockreg_p)yioremap(CLOCKBASE,sizeof(t_clockreg),"clkio");    //remap clock and power registers base address

if(_padcdev->pclkreg==NULL){

rs=-EBUSY;                            //clock register was used by other device

goto fail2;

}

else{

_padcdev->pclkreg->CLKCON|=SETB(15);    //enable adc clk

yiounmap(CLOCKBASE,_padcdev->pclkreg,sizeof(t_clockreg));    //release the right that uding clock register

}

_padcdev->padcreg=(t_adcregs_p)yioremap(ADCBASE,sizeof(t_adcregs),"adcio");        //remap adc registers base address

if(_padcdev->padcreg==NULL){

rs=-EBUSY;                            //adc register was used by other device

goto fail2;

}

rs=register_chrdev_region(dev,1,YDRIVER_NAME);//register char device

if(rs<0){

rs=-EBUSY;                            //register char device failed

goto fail3;

}

rs=request_irq(IRQ_ADC,on_adc,IRQF_DISABLED,"adc_int",NULL);    //request ADC interruput

if(rs)goto fail4;                            //request ADC interrupt failed

rs=request_irq(IRQ_TC,on_tc,IRQF_DISABLED,"tc_int",NULL);        //request touch screen interrupt

if(rs)goto fail5;                            //request touch screen interrupt failed

_padcdev->counter=0;                        //initialize the tounter to zero

init_timer(&_padcdev->timer);                    //initialize timer

_padcdev->timer.function=&on_timer;            //specify the timer is routine

printk(KERN_INFO"TS driver installed\n");        //tip driver install success

_padcdev->padcreg->ADCCON=(0x1<<14)|(0x13<<6);    //ADC clock=PCLK/(0x13+1)

_padcdev->padcreg->ADCTSC=0xd3;            //Waiting for Interrupt Mode

return rs;

fail5:

free_irq(IRQ_ADC,NULL);                    //free adc irq

fail4:

unregister_chrdev_region(MKDEV(YMAJOR,0),1);    //unregister the char device

fail3:

yiounmap(ADCBASE,_padcdev->padcreg,sizeof(t_adcregs));    //unremap ADC registeres

fail2:

kfree(_padcdev);                            //free device space

fail1:

return rs;

}

void __exit exit_adc(void)

{

free_irq(IRQ_TC,NULL);        //free touch screen irq

free_irq(IRQ_ADC,NULL);    //free adc irq

del_timer(&_padcdev->timer);    //delete timer

yiounmap(ADCBASE,_padcdev->padcreg,sizeof(t_adcregs));    //unremap ADC registeres

kfree(_padcdev);            //free device space

unregister_chrdev_region(MKDEV(YMAJOR,0),1);    //unregister the char device

}

module_init(init_adc);    //register the module for initialize driver

module_exit(exit_adc);    //register the module for release driver

MODULE_AUTHOR("MrY");    //driver's author

MODULE_VERSION("0.1");    //driver's version

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值