驱动程序之_1_字符设备_12_触摸屏驱动

驱动程序之_1_字符设备_12_触摸屏驱动

触摸屏在内核中有现成的input子系统框架,input_handler层位于ts_dev.c,只需要编写input_dev层与之融合即可,编写方法与lcd驱动程序类似

一、在入口函数
1、分配input_dev结构体

s3c_ts_dev = input_allocate_device();

2、设置input_dev结构体
3、注册input_dev结构体
4、硬件初始化
①、使能时钟

	struct clk *adc_clk;

	adc_clk = clk_get(0, "adc");
	clk_enable(adc_clk);

②、IO映射,触摸屏、ADC控制器配置
③、初始化定时器
④、申请中断

二、在出口函数
1、硬件相关
①、注销中断
②、删除定时器
③、取消IO映射
④、关闭时钟

2、注销input_dev结构体
3、销毁input_dev结构体

三、编写功能函数
1、触摸屏中断服务程序
①、判断按下还是松开
②、按下时,开启定时器;松开时上报事件

2、ADC中断服务程序
①、判断是否仍按下
②、已松开,上报事件
③、仍按下,取出ADC转换数值处理
④、按下的情况下,若满足条件(例程中条件是已算出多次数据的平均值,并且每次数据相差不是特别大),上报事件

3、定时器中断服务程序
①、判断是否仍按下
②、已松开,上报事件
③、仍按下,开启一次ADC转换

4、其他子程序

测试方法:
一、将例程中上报事件的相关代码换成串口打印输出
加载驱动后,按下屏幕即可从串口看到输出信息

二、使用例程驱动,配合lcd驱动和tslib库测试
1、安装tslib库,并移动到开发板上
①、解压

tar xzf tslib-1.4.tar.gz

②、进入tslib目录,配置

cd tslib
./autogen.sh 

③、编译、安装,其中tmp是临时目录(tslib临时安装到该目录,nfsroot是开发板根目录)

mkdir tmp

echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache

./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp

make

make install

cd tmp
cp * -rf /nfsroot

2、配置tslib库

vi /etc/ts.conf

修改配置文件

# module_raw input

module_raw input

配置,其中
event0 是加载触摸屏驱动时增加的event设备(可能不是0,根据实际情况修改)
fb0 是加载lcd驱动时增加的fb设备(可能不是0,根据实际情况修改)

export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0

3、按照上篇中的方法,重新编译内核(反选触摸屏驱动),用新内核启动

4、加载lcd驱动、触摸屏驱动

5、使用tslib库测试
①、校准

ts_calibrate

触摸屏上依次按下准心,完成屏幕校准

②、测试

ts_test

点击drag,可以拖动十字准心移动
点击draw,可以在屏幕上画图写字
同时串口会输出相关信息

附上程序代码

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/input.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <asm/mach/map.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/fb.h>

#define MEASURE_TIMES 4


struct s3c_ts_regs{
	volatile unsigned long adccon;
	volatile unsigned long adctsc;
	volatile unsigned long adcdly;
	volatile unsigned long adcdat0;
	volatile unsigned long adcdat1;
	volatile unsigned long adcupdn;
};


static struct input_dev *s3c_ts_dev;
static volatile struct s3c_ts_regs *s3c_ts_regs;

static void enter_wait_pen_down_mode(void)
{
	s3c_ts_regs->adctsc = 0xd3;
}

static void enter_wait_pen_up_mode(void)
{
	s3c_ts_regs->adctsc = 0x1d3;
}

static void enter_measure_mode(void)
{
	s3c_ts_regs->adctsc = (1<<3) | (1<<2);
}

static void adc_start(void)
{
	s3c_ts_regs->adccon |= 1;
}


static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
{
	if(s3c_ts_regs->adcdat0 & (1<<15))
	{
		enter_wait_pen_down_mode();		
		input_report_abs(s3c_ts_dev,ABS_PRESSURE,0);
		input_report_key(s3c_ts_dev,BTN_TOUCH,0);
		input_sync(s3c_ts_dev);		
	}
	else
	{
		mod_timer(&s3c_ts_dev->timer,jiffies + HZ/100);
	}

	return IRQ_RETVAL(IRQ_HANDLED);
}

static int filter_xy(int x[], int y[], int num)
{
#define ERR_MAX 10
	int tmp_x, tmp_y;
	int del_x, del_y;
	int i;

	for(i = 0;i < num-1;i+=2)
	{
		tmp_x  = x[i] + x[i+1];	
		tmp_x /= 2;
		tmp_y  = y[i] + y[i+1];	
		tmp_y /= 2;

		if(i == (num-2))
		{			
			del_x = tmp_x > x[0] ? tmp_x-x[0] : x[0]-tmp_x;
			del_y = tmp_y > y[0] ? tmp_y-y[0] : y[0]-tmp_y;		
		}else
		{
			del_x = tmp_x > x[i+2] ? tmp_x-x[i+2] : x[i+2]-tmp_x;
			del_y = tmp_y > y[i+2] ? tmp_y-y[i+2] : y[i+2]-tmp_y;
		}
		
		if((del_x > ERR_MAX) || (del_y > ERR_MAX))
			return -1;
	}

	return 0;
}

static irqreturn_t ts_adc_irq(int irq ,void *dev_id)
{
	static int adcdat0 ,adcdat1;
	static int x[MEASURE_TIMES], y[MEASURE_TIMES];
	int x_avg = 0, y_avg = 0;
	static int i = 0;

	adcdat0 = s3c_ts_regs->adcdat0;
	adcdat1 = s3c_ts_regs->adcdat1;

	if(s3c_ts_regs->adcdat0 & (1<<15))
	{
		i = 0;
		enter_wait_pen_down_mode();
		input_report_abs(s3c_ts_dev,ABS_PRESSURE,0);
		input_report_key(s3c_ts_dev,BTN_TOUCH,0);
		input_sync(s3c_ts_dev);		
	}
	else
	{		
		x[i] = adcdat0 & 0x3ff;
		y[i] = adcdat1 & 0x3ff;	
		i++;
		if(i == MEASURE_TIMES)
		{
			if(!filter_xy(x,y,MEASURE_TIMES))
			{
			
				for(i = 0;i < MEASURE_TIMES;i++)
				{
					x_avg += x[i];
					y_avg += y[i];
				}
								
				x_avg /= MEASURE_TIMES;
				y_avg /= MEASURE_TIMES;			
//				printk("average : x=%d,y=%d\r\n",x_avg,y_avg);
				input_report_abs(s3c_ts_dev,ABS_X,x_avg);
//				input_event(s3c_ts_dev,EV_ABS,ABS_X,x_avg);
				input_report_abs(s3c_ts_dev,ABS_Y,y_avg);
//				input_event(s3c_ts_dev,EV_ABS,ABS_Y,y_avg);
				input_report_abs(s3c_ts_dev,ABS_PRESSURE,1);
//				input_event(s3c_ts_dev,EV_ABS,ABS_PRESSURE,1);
				input_report_key(s3c_ts_dev,BTN_TOUCH,1);
//				input_event(s3c_ts_dev,EV_KEY,BTN_TOUCH,1);
				input_sync(s3c_ts_dev);
			}
			i = 0;		
	
			enter_wait_pen_up_mode();
			mod_timer(&s3c_ts_dev->timer,jiffies + HZ/100);
		}
		else
		{			
			enter_measure_mode();
			adc_start();				
		}		
	}
	

	return IRQ_RETVAL(IRQ_HANDLED);
}

static void s3c_ts_timer_func(unsigned long data)
{
	if(s3c_ts_regs->adcdat0 & (1<<15))
	{
		enter_wait_pen_down_mode();
		input_report_abs(s3c_ts_dev,ABS_PRESSURE,0);
		input_report_key(s3c_ts_dev,BTN_TOUCH,0);
		input_sync(s3c_ts_dev);		
	}
	else
	{					
		enter_measure_mode();
		adc_start();		
	}
}

static int s3c_ts_init(void)
{
	struct clk *adc_clk;
	int error;
	
	s3c_ts_dev = input_allocate_device();

	strcmp(s3c_ts_dev->name,"s3c_ts");


	set_bit(EV_KEY,s3c_ts_dev->evbit);		
	set_bit(EV_ABS,s3c_ts_dev->evbit);


	set_bit(BTN_TOUCH,s3c_ts_dev->keybit);
	input_set_abs_params(s3c_ts_dev, ABS_X,0, 0x3ff, 0, 0);
	input_set_abs_params(s3c_ts_dev, ABS_X,0, 0x3ff, 0, 0);
	input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
	
	input_register_device(s3c_ts_dev);

	adc_clk = clk_get(0, "adc");
	clk_enable(adc_clk);

	s3c_ts_regs = ioremap(0x58000000,sizeof(struct s3c_ts_regs));
	s3c_ts_regs->adccon = (1<<14) | (49<<6);
	s3c_ts_regs->adcdly = 0xffff;


	init_timer(&s3c_ts_dev->timer);
	s3c_ts_dev->timer.function = s3c_ts_timer_func;
	add_timer(&s3c_ts_dev->timer);

	error = request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "s3c_ts_pen_irq" ,0);
	error = request_irq(IRQ_ADC, ts_adc_irq, IRQF_SAMPLE_RANDOM, "s3c_ts_adc_irq" ,0);

	enter_wait_pen_down_mode();	
	
	return 0;
}

static void s3c_ts_exit(void)
{
	struct clk *adc_clk;

	free_irq(IRQ_TC, 0);
	
	del_timer(&s3c_ts_dev->timer);
	
	iounmap(s3c_ts_regs);
	
	clk_get("adc");
	clk_disable();
	
	input_unregister_device(s3c_ts_dev);	
	input_free_device(s3c_ts_dev);
}

module_init(s3c_ts_init);
module_exit(s3c_ts_exit);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值