硬件渠道:FL2440
内核版别:2.6.28
主机渠道:Ubuntu 11.04
内核版别:2.6.39
1、下面是ADC和角度屏接口的模块图
当角度屏接口运用时,XM或YM接角度屏接口的地
当角度屏接口不运用时,XM或YM接模拟信号,做一般ADC运用。
2、角度屏接口的几种操作形式
(1) 正常转化形式
经过设置ADCCON(adc操控寄存器)来完结初始化,并对ADCDAT0数据寄存器进行操作。
(2) 别离XY坐标形式
X坐标形式写X坐标转化数据到ADCDAT0,角度屏接口发生中止到中止操控寄存器。Y坐标形式写Y坐标转化数据到ADCDAT1,角度屏接口发生中止到中止操控寄存器。两种模
式能够挑选一种形式作业。
相应的引脚衔接:
(3) 主动XY坐标形式
角度屏操控器接连的转化X和Y的坐标,在X坐标转化后的值存入ADCDAT0后,主动将Y坐标转化后的值存入ADCDAT1,角度屏接口发生中止到中止操控器。
相应的引脚衔接:
(4) 等候中止形式
当光标被按下,角度屏操控器发生中止IRQ_TC,当发生中止信号时,等候中止形式有必要被铲除。
引脚界说如下:
3、下面是s3c2440角度屏驱动的剖析
- //#defineCONFIG_TOUCHSCREEN_S3C2410_DEBUG
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #defineTRUE1//CoAsiaadded
- #defineFALSE0//CoAsiaadded
- #defineFILTER_LIMIT25//CoAsiaadded
- /*Forts.dev.id.version*/
- #defineS3C2410TSVERSION0x0101
- #defineTSC_SLEEP(S3C2410_ADCTSC_PULL_UP_DISABLE|S3C2410_ADCTSC_XY_PST(0))
- #defineWAIT4INT(x)(((x)<<8)|\
- S3C2410_ADCTSC_YM_SEN|S3C2410_ADCTSC_YP_SEN|S3C2410_ADCTSC_XP_SEN|\
- S3C2410_ADCTSC_XY_PST(3))
- #defineAUTOPST(S3C2410_ADCTSC_YM_SEN|S3C2410_ADCTSC_YP_SEN|S3C2410_ADCTSC_XP_SEN|\
- S3C2410_ADCTSC_AUTO_PST|S3C2410_ADCTSC_XY_PST(0))
- #defineDEBUG_LVL”<3>“//KERN_DEBUG
- staticchar*s3c2440ts_name=”s3c2440TouchScreen”;
- /*
- *Per-touchscreendata.
- */
- //界说s3c2440角度屏运用的数据结构体
- structs3c2440ts{
- structinput_dev*dev;
- longxp;
- longyp;
- intcount;
- intshift;
- };
- staticstructs3c2440tsts;
- staticstructclk*adc_clock;
- //__iomem声明地址空间是设备地址映射空间
- staticvoid__iomem*base_addr;
- //函数声明
- staticvoidtouch_timer_fire(unsignedlongdata);
- staticirqreturn_ttc_irq(intirq,void*dev_id);
- staticirqreturn_tadc_irq(intirq,void*dev_id);
- staticint__inits3c2440ts_probe(structplatform_device*pdev);
- staticints3c2440ts_remove(structplatform_device*pdev);
- staticints3c2440ts_resume(structplatform_device*pdev);
- //界说定时器
- staticstructtimer_listtouch_timer=
- TIMER_INITIALIZER(touch_timer_fire,0,0);
- //IRQ_TC中止处理函数
- staticirqreturn_ttc_irq(intirq,void*dev_id)
- {
- //data0,data1用于寄存读取的ADCDAT数据寄存器的值
- unsignedlongdata0;
- unsignedlongdata1;
- intupdown;//用于寄存光标的按下或提起的状况
- //读取ADCDAT0、ADCDAT1数据寄存器的值
- data0=readl(base_addr+S3C2410_ADCDAT0);
- data1=readl(base_addr+S3C2410_ADCDAT1);
- //检查数据寄存器的第15位的值
- updown=(!(data0&S3C2410_ADCDAT0_UPDOWN))&&(!(data1&S3C2410_ADCDAT0_UPDOWN));
- /*TODOweshouldnevergetaninterruptwithupdownsetwhile
- *thetimerisrunning,butmaybeweoughttoverifythatthe
- *timerisntrunninganyways.*/
- //假如data0和data1的第15位都是0,则updown为1,则经过函数touch_timer_fire()函数来发动ADC转化
- if(updown)
- touch_timer_fire(0);
- returnIRQ_HANDLED;
- }
- staticvoidtouch_timer_fire(unsignedlongdata)
- {
- //用于存储数据寄存器ADCDAT0、ADCDAT1的值
- unsignedlongdata0;
- unsignedlongdata1;
- //用于寄存光标是否被按下
- intupdown;
- data0=readl(base_addr+S3C2410_ADCDAT0);
- data1=readl(base_addr+S3C2410_ADCDAT1);
- updown=(!(data0&S3C2410_ADCDAT0_UPDOWN))&&(!(data1&S3C2410_ADCDAT0_UPDOWN));
- //printk(“Thenumberofupdownis%d\n”,updown);
- //假如光标被按下,碑文
- if(updown)
- {
- //ts.count!=0一共ADC现已转化过,下面就陈述事情和光标方位数据
- if(ts.count!=0)
- {
- ts.xp>>=ts.shift;//这儿shift为2,这儿实际上是求均值,四次的和/4,这样定位愈加精确
- ts.yp>>=ts.shift;
- #ifdefCONFIG_TOUCHSCREEN_S3C2410_DEBUG
- {
- structtimevaltv;
- do_gettimeofday(&tv);
- printk(DEBUG_LVL”T:%06d,X:%03ld,Y:%03ld\n”,(int)tv.tv_usec,ts.xp,ts.yp);
- }
- #endif
- /*
- 下面的函数坐落/include/linux/input.h,作用是陈述事情
- staticinlinevoidinput_report_abs(structinput_dev*dev,unsignedintcode,intvalue)
- {
- input_event(dev,EV_ABS,code,value);
- }
- */
- //陈述X,Y的肯定坐标
- input_report_abs(ts.dev,ABS_X,ts.xp);
- input_report_abs(ts.dev,ABS_Y,ts.yp);
- //陈述事情,1代表光标被按下
- input_report_key(ts.dev,BTN_TOUCH,1);
- //陈述角度屏状况,1代表角度屏被按下
- input_report_abs(ts.dev,ABS_PRESSURE,1);
- //等候接收方的结语,用于事情的同步
- input_sync(ts.dev);
- }
- //现在光标被按下,而且ADC转化没有发动
- ts.xp=0;
- ts.yp=0;
- ts.count=0;
- //设置角度屏操控寄存器的值为0xdcB:11011100,设置操控寄存器上拉无效,主动转化X,Y坐标
- //printk(“S3C2410_ADCTSC:0x%x\n”,S3C2410_ADCTSC_PULL_UP_DISABLE|AUTOPST);
- writel(S3C2410_ADCTSC_PULL_UP_DISABLE|AUTOPST,base_addr+S3C2410_ADCTSC);
- //发动ADC转化
- writel(readl(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_ENABLE_START,base_addr+S3C2410_ADCCON);
- }
- else//光标没有被按下
- {
- ts.count=0;
- //陈述事情及光标的方位状况
- input_report_key(ts.dev,BTN_TOUCH,0);
- input_report_abs(ts.dev,ABS_PRESSURE,0);
- //等候接收方的应对,用于同步
- input_sync(ts.dev);
- //设置角度屏操控寄存器为等候中止形式
- writel(WAIT4INT(0),base_addr+S3C2410_ADCTSC);
- }
- }
- staticirqreturn_tadc_irq(intirq,void*dev_id)
- {
- //用于寄存数据寄存器的数据
- unsignedlongdata0;
- unsignedlongdata1;
- //读取数据,这次首要读取的是方位数据
- data0=readl(base_addr+S3C2410_ADCDAT0);
- data1=readl(base_addr+S3C2410_ADCDAT1);
- ts.xp+=data0&S3C2410_ADCDAT0_XPDATA_MASK;//累加四次准换成果的X坐标和
- ts.yp+=data1&S3C2410_ADCDAT1_YPDATA_MASK;//累加四次准换成果的Y坐标和
- ts.count++;//转化次数加一
- //假如转化次数小于4
- if(ts.count<(1<
- {
- //再次设置角度屏操控寄存器上拉不使能、主动X、Y转化形式
- writel(S3C2410_ADCTSC_PULL_UP_DISABLE|AUTOPST,base_addr+S3C2410_ADCTSC);
- //再次发动ADC转化
- writel(readl(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_ENABLE_START,base_addr+S3C2410_ADCCON);
- }
- else//这时,ADC转化四次完结,推迟一个体系滴答,碑文touch_timer_fire()函数
- {
- mod_timer(&touch_timer,jiffies+1);
- writel(WAIT4INT(1),base_addr+S3C2410_ADCTSC);
- }
- returnIRQ_HANDLED;
- }
- /*
- *Thefunctionsforinserting/removingusasamodule.
- */
- /*
- 该结构体界说在/include/linux/platform_device.h
- structplatform_device{
- constchar*name;
- intid;
- structdevicedev;
- u32num_resources;
- structresource*resource;
- };
- */
- staticint__inits3c2440ts_probe(structplatform_device*pdev)
- {
- intrc;
- /*
- 下面结构体界说在/include/mach/s3c2410_ts.h
- structs3c2410_ts_mach_info{
- intdelay;
- intpresc;
- intoversampling_shift;
- };
- */
- structs3c2410_ts_mach_info*info;
- structinput_dev*input_dev;
- /*
- void*platform_data;//Platformspecificdata,devicecoredoesnttouchit
- */
- info=(structs3c2440_ts_mach_info*)pdev->dev.platform_data;
- if(!info)
- {
- printk(KERN_ERR”Hm…toobad:noplatformdataforts\n”);
- return-EINVAL;
- }
- #ifdefCONFIG_TOUCHSCREEN_S3C2410_DEBUG
- printk(DEBUG_LVL”Enterings3c2440ts_init\n”);
- #endif
- //我们ADC转化需求时钟,这儿获取时钟
- adc_clock=clk_get(NULL,”adc”);
- if(!adc_clock){
- printk(KERN_ERR”failedtogetadcclocksource\n”);
- return-ENOENT;
- }
- clk_enable(adc_clock);//使能时钟
- #ifdefCONFIG_TOUCHSCREEN_S3C2410_DEBUG
- printk(DEBUG_LVL”gotandenabledclock\n”);
- #endif
- //经过ioremap完成物理地址到虚拟地址的转化
- base_addr=ioremap(S3C2410_PA_ADC,0x20);
- if(base_addr==NULL){
- printk(KERN_ERR”Failedtoremapregisterblock\n”);
- return-ENOMEM;
- }
- //设置ADCCON操控寄存器为0x4c40,设置预分频有用,预分频值为B:110001D:49
- //printk(“ADCCONis0x%x\n”,S3C2410_ADCCON_PRSCEN|S3C2410_ADCCON_PRSCVL(info->presc&0xFF));
- if((info->presc&0xff)>0)
- writel(S3C2410_ADCCON_PRSCEN|S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
- base_addr+S3C2410_ADCCON);
- else
- writel(0,base_addr+S3C2410_ADCCON);
- /*Initialiseregisters*/
- /*
- 设置ADC开端延时寄存器ADCDLY:0x4e20
- */
- //printk(“ADCDLY:0x%x\n”,info->delay&0xffff);
- if((info->delay&0xffff)>0)
- writel(info->delay&0xffff,base_addr+S3C2410_ADCDLY);
- /*
- 设置ADC角度屏操控寄存器ADC_TSC:0xd3B:11010011
- [8]检测光标按下中止信号
- [7]YM输出驱动有用(GND)
- [6]YP输出驱动无效(AIN5)
- [5]XM输出驱动无效(Hi-z)
- [4]XP输出驱动无效(AIN7)
- [3]XP上拉有用
- [2]一般ADC转化
- [0:1]等候中止形式丈量X和Y的坐标
- */
- //printk(“ADC_TSC:0x%x\n”,WAIT4INT(0));
- writel(WAIT4INT(0),base_addr+S3C2410_ADCTSC);
- /*Initialiseinputstuff*/
- memset(&ts,0,sizeof(structs3c2440ts));
- /*
- 下面的函数
- 为新的输入设备分配内存。
- 运用free_device()开释没有被注册的函数,运用input_unregister_device()免除现已注册的设备
- 界说在/drivers/input/input.c
- structinput_dev*input_allocate_device(void)
- {
- structinput_dev*dev;
- dev=kzalloc(sizeof(structinput_dev),GFP_KERNEL);
- if(dev){
- dev->dev.type=&input_dev_type;
- dev->dev.class=&input_class;
- device_initialize(&dev->dev);
- mutex_init(&dev->mutex);
- spin_lock_init(&dev->event_lock);
- INIT_LIST_HEAD(&dev->h_list);
- INIT_LIST_HEAD(&dev->node);
- __module_get(THIS_MODULE);
- }
- returndev;
- }
- */
- input_dev=input_allocate_device();
- if(!input_dev){
- printk(KERN_ERR”Unabletoallocatetheinputdevice!!\n”);
- return-ENOMEM;
- }
- //下面初始化输入设备信息
- ts.dev=input_dev;
- ts.dev->evbit[0]=BIT_MASK(EV_SYN)|BIT_MASK(EV_KEY)|
- BIT_MASK(EV_ABS);
- ts.dev->keybit[BIT_WORD(BTN_TOUCH)]=BIT_MASK(BTN_TOUCH);
- 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);
- //ts.dev->private=&ts;
- ts.dev->name=s3c2440ts_name;
- ts.dev->id.bustype=BUS_RS232;
- ts.dev->id.vendor=0xDEAD;
- ts.dev->id.product=0xBEEF;
- ts.dev->id.version=S3C2410TSVERSION;
- ts.shift=info->oversampling_shift;
- //printk(“shift:%d\n”,ts.shift);
- /*Getirqs*/
- //请求ADC中止,留意,中止类型为IRQF_SAMPLE_RANDOM|IRQF_SHARED,这样在运用角度屏的时分
- //能够调试自己的ADC转化驱动,中止处理函数为adc_irq
- if(request_irq(IRQ_ADC,adc_irq,IRQF_SAMPLE_RANDOM|IRQF_SHARED,
- “s3c2440_action”,ts.dev)){
- printk(KERN_ERR”s3c2440_ts.c:CouldnotallocatetsIRQ_ADC!\n”);
- iounmap(base_addr);
- return-EIO;
- }
- //请求TC中止,中止处理函数为tc_irq
- if(request_irq(IRQ_TC,tc_irq,IRQF_SAMPLE_RANDOM,
- “s3c2440_action”,ts.dev)){
- printk(KERN_ERR”s3c2440_ts.c:CouldnotallocatetsIRQ_TC!\n”);
- free_irq(IRQ_ADC,ts.dev);
- iounmap(base_addr);
- return-EIO;
- }
- printk(KERN_INFO”%ssuccessfullyloaded\n”,s3c2440ts_name);
- /*Allwentok,soregistertotheinputsystem*/
- /*这儿注册设备
- 函数功用:
- *Thisfunctionregistersdevicewithinputcore.Thedevicemustbe
- *allocatedwithinput_allocate_device()andallitscapabilities
- *setupbeforeregistering.
- *Iffunctionfailsthedevicemustbefreedwithinput_free_device().
- *Oncedevicehasbeensuccessfullyregistereditcanbeunregistered
- *withinput_unregister_device();input_free_device()shouldnotbe
- *calledinthiscase.
- 函数原型如下:
- intinput_register_device(structinput_dev*dev)
- {
- staticatomic_tinput_no=ATOMIC_INIT(0);
- structinput_handler*handler;
- constchar*path;
- interror;
- __set_bit(EV_SYN,dev->evbit);
- init_timer(&dev->timer);
- if(!dev->rep[REP_DELAY]&&!dev->rep[REP_PERIOD]){
- dev->timer.data=(long)dev;
- dev->timer.function=input_repeat_key;
- dev->rep[REP_DELAY]=250;
- dev->rep[REP_PERIOD]=33;
- }
- if(!dev->getkeycode)
- dev->getkeycode=input_default_getkeycode;
- if(!dev->setkeycode)
- dev->setkeycode=input_default_setkeycode;
- snprintf(dev->dev.bus_id,sizeof(dev->dev.bus_id),
- “input%ld”,(unsignedlong)atomic_inc_return(&input_no)-1);
- error=device_add(&dev->dev);
- if(error)
- returnerror;
- path=kobject_get_path(&dev->dev.kobj,GFP_KERNEL);
- printk(KERN_INFO”input:%sas%s\n”,
- dev->name?dev->name:”Unspecifieddevice”,path?path:”N/A”);
- kfree(path);
- error=mutex_lock_interruptible(&input_mutex);
- if(error){
- device_del(&dev->dev);
- returnerror;
- }
- list_add_tail(&dev->node,&input_dev_list);
- list_for_each_entry(handler,&input_handler_list,node)
- input_attach_handler(dev,handler);
- input_wakeup_procfs_readers();
- mutex_unlock(&input_mutex);
- return0;
- }
- */
- rc=input_register_device(ts.dev);
- if(rc){
- free_irq(IRQ_TC,ts.dev);
- free_irq(IRQ_ADC,ts.dev);
- clk_disable(adc_clock);
- iounmap(base_addr);
- return-EIO;
- }
- return0;
- }
- staticints3c2440ts_remove(structplatform_device*pdev)
- {
- disable_irq(IRQ_ADC);
- disable_irq(IRQ_TC);
- free_irq(IRQ_TC,ts.dev);
- free_irq(IRQ_ADC,ts.dev);
- if(adc_clock){
- clk_disable(adc_clock);
- clk_put(adc_clock);
- adc_clock=NULL;
- }
- input_unregister_device(ts.dev);
- iounmap(base_addr);
- return0;
- }
- #ifdefCONFIG_PM
- staticints3c2440ts_suspend(structplatform_device*pdev,pm_message_tstate)
- {
- writel(TSC_SLEEP,base_addr+S3C2410_ADCTSC);
- writel(readl(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_STDBM,
- base_addr+S3C2410_ADCCON);
- disable_irq(IRQ_ADC);
- disable_irq(IRQ_TC);
- clk_disable(adc_clock);
- return0;
- }
- staticints3c2440ts_resume(structplatform_device*pdev)
- {
- structs3c2440_ts_mach_info*info=
- (structs3c2440_ts_mach_info*)pdev->dev.platform_data;
- clk_enable(adc_clock);
- msleep(1);
- enable_irq(IRQ_ADC);
- enable_irq(IRQ_TC);
- if((info->presc&0xff)>0)
- writel(S3C2410_ADCCON_PRSCEN|S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
- base_addr+S3C2410_ADCCON);
- else
- writel(0,base_addr+S3C2410_ADCCON);
- /*Initialiseregisters*/
- if((info->delay&0xffff)>0)
- writel(info->delay&0xffff,base_addr+S3C2410_ADCDLY);
- writel(WAIT4INT(0),base_addr+S3C2410_ADCTSC);
- return0;
- }
- #else
- #defines3c2440ts_suspendNULL
- #defines3c2440ts_resumeNULL
- #endif
- /*
- 下面是/linux/platform_device.h界说的platform_driver结构体
- structplatform_driver{
- int(*probe)(structplatform_device*);//设备的检测,所以需求从前的设备注册
- int(*remove)(structplatform_device*);//删去该设备
- void(*shutdown)(structplatform_device*);//关闭该设备
- int(*suspend)(structplatform_device*,pm_message_tstate);
- int(*suspend_late)(structplatform_device*,pm_message_tstate);
- int(*resume_early)(structplatform_device*);
- int(*resume)(structplatform_device*);
- structpm_ext_ops*pm;
- structdevice_driverdriver;//设备驱动,界说在include/linux/device.h中
- };
- 内核供给的platform_driver结构体的注册函数为platform_driver_register(),该函数界说在driver/base/platform.c中
- */
- staticstructplatform_drivers3c2440ts_driver={
- .driver={
- .name=”s3c2440-ts”,
- .owner=THIS_MODULE,
- },
- .probe=s3c2440ts_probe,
- .remove=s3c2440ts_remove,
- .suspend=s3c2440ts_suspend,
- .resume=s3c2440ts_resume,
- };
- staticint__inits3c2440ts_init(void)
- {
- intrc;
- rc=platform_driver_register(&s3c2440ts_driver);
- if(rc<0)
- printk(KERN_ERR”platform_driver_registererror!\n”);
- returnrc;
- }
- staticvoid__exits3c2440ts_exit(void)
- {
- platform_driver_unregister(&s3c2440ts_driver);
- }
- module_init(s3c2440ts_init);
- module_exit(s3c2440ts_exit);
- MODULE_AUTHOR(“YANMING”);
- MODULE_DESCRIPTION(“Mys3c2440touchscreendriver”);
- MODULE_L%&&&&&%ENSE(“GPL”);
4、剖析完结后对角度屏的作业进程就有了一个比较清晰的知道
从角度屏被按下到体系相应的进程如下:
(1) 当角度屏感觉到角度,触发IRQ_TC中止,然后读取角度屏操控寄存器的值,判别是否被按下,假如被按下,发动定时器,碑文touch_timer_fire()函数发动ADC转化。
(2) ADC转化完结后,会触发IRQ_ADC中止,碑文相应的中止处理函数,假如ADC转化次数小于4,再次发动ADC转化;假如ADC转化次数为4,则发动一个体系滴答定时器,碑文touch_timer_fire()函数
(3) 碑文定时器服务程序时,假如此刻角度屏仍被按下,则上报事情和坐标数据,重复(2);假如没有被按下,上报时刻和坐标数据,将角度屏操控寄存器设置为中止等候状况
可见,角度屏驱动的服务是一个关闭的循环进程。