嵌入式linux驱动-触摸屏笔记

2019-07-12 14:44发布

一、开发环境 1、内核:Linux 2.6.22.6; 2、JZ2440v3 3、ubuntu 9.10 二、过程
三、程序 #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include static struct input_dev *myts_dev; static struct timer_list ts_time; struct ts_regs{ unsigned long adccon; unsigned long adctsc; unsigned long adcdly; unsigned long adcdat0; unsigned long adcdat1; unsigned long adcupdn; }; static volatile struct ts_regs *ts_regs; static int enter_pen_up_mode(void) { ts_regs->adctsc=0x1d3; return 0; } static void enter_pen_down_mode(void) { ts_regs->adctsc=0xd3; } static void enter_measure_xy_mode(void) { ts_regs->adctsc=(1<<3)|(1<<2)|(3<<0); } static void start_adc(void) { ts_regs->adccon |=(1<<0); } static int filter_ts(int x[],int y[]) { #define ERR_LIMIT 10 int avr_x, avr_y; int det_x, det_y; avr_x = (x[0] + x[1])/2; avr_y = (y[0] + y[1])/2; det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]); det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 0; avr_x = (x[1] + x[2])/2; avr_y = (y[1] + y[2])/2; det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]); det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 0; return 1; } static int adc_irq(int irq,void *dev_id) { static int cnt; static int x[4],y[4]; int adcdat0,adcdat1; adcdat0=ts_regs->adcdat0 & 0x3ff; adcdat1=ts_regs->adcdat1 & 0x3ff; if(ts_regs->adcdat0 &(1<<15)) { //已经松开 cnt=0; input_report_abs(myts_dev, ABS_PRESSURE, 0); input_report_key(myts_dev, BTN_TOUCH,0); input_sync(myts_dev); enter_pen_down_mode(); } else { //未松开 x[cnt]=adcdat0; y[cnt]=adcdat1; ++cnt; if(cnt==4) { if(filter_ts( x,y)) //printk("adc_irq cnt=%d,x=%d,y=%d ",cnt,(x[0]+x[1]+x[2]+x[3])/4,(y[0]+y[1]+y[2]+y[3])/4); input_report_abs(myts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4); input_report_abs(myts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4); input_report_abs(myts_dev, ABS_PRESSURE, 1); input_report_key(myts_dev, BTN_TOUCH, 1); input_sync(myts_dev); cnt=0; enter_pen_up_mode(); //启动定时器处理长按滑动的情况 mod_timer(&ts_time, jiffies+HZ/100); } else { enter_measure_xy_mode(); start_adc(); } } return IRQ_HANDLED; } static void ts_timer_function(unsigned long data) { if(ts_regs->adcdat0 &(1<<15)) { //已经松开,进入等待按下模式 input_report_abs(myts_dev, ABS_PRESSURE, 0); input_report_key(myts_dev, BTN_TOUCH,0); input_sync(myts_dev); enter_pen_down_mode(); } else {//否则再次启动转换测量xy坐标 enter_measure_xy_mode(); start_adc(); } //return IRQ_HANDLED; } static int pen_updown_irq(int irq,void *dev_id) { if(ts_regs->adcdat0 &(1<<15)) { printk("pen_up! "); enter_pen_down_mode(); } else { printk("pen_down! "); //enter_pen_up_mode(); enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; } static int ts_init(void) { static struct clk *adc_clock; //1.分配一个input_dev结构体 myts_dev=input_allocate_device(); //2设置 //2.1能产生那类事件 set_bit(EV_KEY,myts_dev->evbit); set_bit(EV_ABS,myts_dev->evbit); //2.2能产生这类事件里的那类事件 set_bit(BTN_TOUCH,myts_dev->keybit); input_set_abs_params(myts_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(myts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(myts_dev, ABS_PRESSURE, 0, 1, 0, 0); //3注册 input_register_device(myts_dev); //4硬件相关的操作 //4.1使能时钟 adc_clock = clk_get(NULL, "adc"); clk_enable(adc_clock); //4.2设置s3c2410触摸屏寄存器 ts_regs=ioremap(0x58000000, sizeof(struct ts_regs)); ts_regs->adccon=(1<<14)|(49<<6); request_irq(IRQ_TC, pen_updown_irq, IRQF_SAMPLE_RANDOM,"ts_action", NULL); request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM,"ts_adc", NULL); //优化延时 ts_regs->adcdly=0xffff; //使用定时器 处理 长按滑动的情况 init_timer(&ts_time); ts_time.function=ts_timer_function; add_timer(&ts_time); enter_pen_down_mode(); return 0; } static void ts_exit(void) { free_irq(IRQ_TC, NULL); free_irq(IRQ_ADC, NULL); iounmap(ts_regs); input_unregister_device(myts_dev); input_free_device(myts_dev); del_timer(&ts_time); } module_init(ts_init); module_exit(ts_exit); MODULE_LICENSE("GPL");