一、输入子系统
核心层: Linux_Dir/drivers/input/input.c(提供最核心函数)
设备事件层: Linux_Dir/drivers/input/evdev.c(提供handler)
提供输入设备产生的原始数据并上报给应用程序,这适用于
所有输入设备, 该触摸屏也不例外
编写基于输入子系统的驱动时只需:
1.分配input_dev
2.设置能产生什么事件和这类事件的哪些事件
3. input_register_device注册
4. 硬件操作
输入子系统需要提供文件读写等函数,在输入子系统中"input.c"中的File_operations结构体中,发现只存在".open"函数
static const struct file_operations input_fops = {
.owner = THIS_MODULE,
.open = input_open_file,
};
在"input_open_file"函数中会发现它依赖其他文件如“evdev.c,keyboard.c”等文件注册的“input_handler”结构(这些结构中提供了 read,write 等函数)。
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5];
const struct file_operations *old_fops, *new_fops = NULL;
int err;
.....
old_fops = file->f_op;
file->f_op = new_fops;
err = new_fops->open(inode, file);
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
触摸屏也是用上面这一套框架来操作的。右边需要一个“evdev.c”文件。左边要分配一个
“input_dev”结构。接着就看上图的硬件设备左边的过程:
分配一个“input_dev”结构体 --> 设置这个"input_dev"结构体 --> 注册这个"input_dev"
结构体 --> 硬件相关的操作。
二、触摸屏硬件原理
三、s3c2440 AD控制器
- A/D converter freq. = 50MHz/(49+1) = 1MHz
- Conversion time = 1/(1MHz / 5cycles) = 1/200KHz = 5 us
需要设置合适的时钟给触摸屏模块,在实验设为1MHz
驱动程序需要通过clk_get和clk_enable使能ADC模块设置adccon的第bit6为49,使得触摸屏时钟为1MHZ
clk = clk_get(NULL, "adc");
clk_enable(clk);
自动的X/Y坐标转换模式,把X坐标存入寄存器ADCDAT0,把Y坐标存入ADCDAT1,驱动程序中可以读
ADCDAT0/1的BIT15获得 转换后的X/Y坐标
等待触摸笔按下或者松开模式,可以通过判断ADCTSC的BIT8是否被设置来知道是等待松开还是等待按下
四、触摸屏使用流程
1.能产生哪类事件
set_bit(EV_KEY, s3c_ts_dev->evbit); //设置input_dev的evdev数组中的EV_KEY位
set_bit(EV_ABS, s3c_ts_dev->evbit);//设置input_dev的evdev数组中的EV_ABS位
2.设置产生这类事件的哪些件
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_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
BIN_TOUCH: 触摸"按键"事件
ABS_X/ABS_Y: X/Y绝对位移
ABS_PRESSURE: 绝对位移压力事件
3.硬件操作
s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));//ioremap寄存器
s3c_ts_regs->adcdly = 0xffff;//设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断
request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
五、代码参考
https://gitee.com/change-ly/linux_drv