基于Tiny4412的电容屏多点触摸驱动程序的简单实现

⑧tiny4412 Linux驱动开发之触摸屏(TouchScreen)驱动程序 本节主要是说一下触摸屏驱动的编写. 触摸屏输入输入设备,所以我们本次通过输入子系统的方式来实现,输入子系统的框架图如下: 然后,我们看一线电路图的触摸屏部分: 可以看到触摸屏是通过I2C接口进行数据和命令的传输,接在了i2c1上面,然后,同时接了一个中断引脚,这个中断引脚主要是在初始化和有数据时使用,比如当用户按下触摸屏产生信息后,首先会产生一个中断,告诉soc有数据来了,这个我们就可... 阅读详情

一、基本开发环境和触摸芯片接口

1、基本开发环境

PC机:Ubuntu12.04 64bit

GCC工具链条:arm-none-linux-gnueabi  (gcc version 4.5.1 (ctng-1.8.1-FA))

开发板:友善之臂Tiny4412

板载系统:Android5.0.2

板载系统内核:Linux-3.0.86

2、触摸芯片接口

从上图中可以看出,触摸芯片和开发板之间通过三条线链接:其中两条是用于IIC数据传输,另外一条是用于中断引脚。


二、驱动程序的编写

1、驱动框架和前期准备

由上面可知驱动触摸芯片和主机之间是通过IIC接口链接的,所以需要使用IIC驱动框架:总线、设备、驱动模型;又考虑到触摸屏最终是通过输入子系统的形式来上报输入事件,所以还需要使用输入子系统驱动框架。所以从驱动程序的总体框架来说:要实现IIC驱动框架和输入子系统驱动框架。

为了更好地编写驱动程序,在开始之前,先定义一些宏来表示驱动程序使用的常量,以及定义一些全局变量或者结构体来更好地维护和方便驱动的开发,这一部分代码的实现如下:

/* 定义触摸驱动的名字 */
#define TINY4412_TS_NAME			"ft5x0x_ts"
#define TINY4412_TS_MAX_X  			800		// x轴最大分辨率
#define TINY4412_TS_MAX_Y  			480		// y轴最大分辨率
#define TINY4412_TS_MAX_ID 			10		// 由硬件来决定

/* 定义一个结构体用来描述触摸点的信息 */
struct yl_tiny4412_ts_event {
	int x;		// 获得的触摸点的x坐标
	int y;		// 获得的触摸点的y坐标
	int id;		// 获得触摸点的id,用来表示对应的触摸点
};

/* 定义一个全局结构体存放相关成员,更好的方便驱动程序的编写 */
struct yl_tiny4412_ts_config
{
	int gpio;			// 定义触摸屏外部中断的GPIO口
	int touch_points;		// 表示当前同时有几个触摸点或者说当前是几点触摸
	struct i2c_client *i2c_client;	// 用于存放i2c_client指针变量
	struct input_dev  *input_dev;	// 定义一个input_dev结构体指针变量
	struct work_struct work_queue;	// 定义工作队列,用来处理和触摸相关的事件
	struct yl_tiny4412_ts_event ts_event[10];	// 定义一个描述触摸点的数组 
};
/* 定义一个 yl_tiny4412_ts_config 结构体的全局变量 */
static struct yl_tiny4412_ts_config yl_tiny4412_ts;
2、IIC框架部分的具体实现

由于IIC驱动程序采用总线、设备、驱动模型来进行实现,所以要自己来实现设备端和驱动端相关的代码。但是在内核中已经实现了设备相关的代码,如下所示:

static struct i2c_board_info i2c_devs1[] __initdata = {
#ifdef CONFIG_TOUCHSCREEN_FT5X0X
	{
		I2C_BOARD_INFO("ft5x0x_ts", (0x70 >> 1)),
		.platform_data = &ft5x0x_pdata,
	},
#endif
	{
		I2C_BOARD_INFO("wm8994", 0x1a),
		.platform_data	= &wm8994_platform_data,
	},
};
所以这里只需要实现IIC驱动端,相关的代码即可。定义一个i2c_driver的结构体变量,具体实现如下:

/* 定义一个id表,用于i2c驱动和设备的匹配 */
static const struct i2c_device_id tiny4412_ts_id[] = {
	{ TINY4412_TS_NAME, 0 },
	{ }
};

/* 定义一个i2c_driver的实例 */
static struct i2c_driver tiny4412_ts_driver = {
	.probe		= tiny4412_ts_probe,
	.remove		= __devexit_p(tiny4412_ts_remove),
	.id_table	= tiny4412_ts_id,
	.driver	= {
		.name	= TINY4412_TS_NAME,
		.owner	= THIS_MODULE,
	},
};
给它添加了一个id_table来匹配设备端代码,在驱动的入口和出口处来注册iic驱动端,代码实现如下:

/* 驱动的入口函数 */
static int __init tiny4412_ts_init(void)
{
	yl_tiny4412_ts.gpio = EXYNOS4_GPX1(6);	// 获得和触摸屏外部中断相关的GPIO口

	return i2c_add_driver(&tiny4412_ts_driver);
}

/* 驱动的出口函数 */
static void __exit tiny4412_ts_exit(void)
{
	i2c_del_driver(&tiny4412_ts_driver);
}
因为在内核中有同名的平台设备,所以这时候平台驱动的probe函数将会被调用。

3、input输入子系统部分实现

可以在iic驱动程序的probe函数当中添加和输入子系统相关的代码,这部分的代码实现如下:

/* 当驱动和设备匹配成功后会调用probe函数 */
static int tiny4412_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = 0;
	
	yl_tiny4412_ts.i2c_client = client;

	/* 1、分配一个input_dev的结构体指针变量 */
	yl_tiny4412_ts.input_dev= input_allocate_device();
	if (!(yl_tiny4412_ts.input_dev)) {
		printk("tiny4412_ts_probe->input_allocate_device error!\n");
		ret = -ENOMEM;
		goto out1;
	}

	/* 2、设置这个结构体变量 */
	/* 2.1 能产生哪类事件 */
	set_bit(EV_SYN, yl_tiny4412_ts.input_dev->evbit);	// 同步事件
	set_bit(EV_ABS, yl_tiny4412_ts.input_dev->evbit);	// 绝对位移类事件

	/* 2.2 能产生该类事件中哪些事件 */
	set_bit(ABS_MT_TRACKING_ID, yl_tiny4412_ts.input_dev->absbit);
	set_bit(ABS_MT_POSITION_X,  yl_tiny4412_ts.input_dev->absbit);
	set_bit(ABS_MT_POSITION_Y,  yl_tiny4412_ts.input_dev->absbit);

	/* 2.3 确定产生的这些事件的范围 */
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_TRACKING_ID, 0, TINY4412_TS_MAX_ID, 0, 0);
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_X, 0, TINY4412_TS_MAX_X, 0, 0);
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_Y, 0, TINY4412_TS_MAX_Y, 0, 0);

	/* 2.4 其他设置 */
	set_bit(INPUT_PROP_DIRECT, yl_tiny4412_ts.input_dev->propbit); 
	yl_tiny4412_ts.input_dev->name = TINY4412_TS_NAME;	// Android系统会根据它找到配置文件

	/* 3、注册这个input_dev结构体指针变量 */
	ret = input_register_device(yl_tiny4412_ts.input_dev);
	if (ret)
	{
		printk("tiny4412_ts_probe->input_register_device error!\n");
		ret = -ENODEV;
		goto out2;
	}	
	
	/* 4、硬件相关的操作 */
	INIT_WORK(&yl_tiny4412_ts.work_queue, tiny4412_work_queue_func);	// 初始化工作队列

	ret = request_irq(gpio_to_irq(yl_tiny4412_ts.gpio), tiny4412_ts_interrupt,
			IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "tiny4412_ts", NULL);
	if (ret)
	{
		printk("tiny4412_ts_probe->request_irq error!\n");
		ret = -EIO;
		goto out3;
	}
	return 0;	// 一切正常则返回0
	
out3:
	input_unregister_device(yl_tiny4412_ts.input_dev);
out2:
	input_free_device(yl_tiny4412_ts.input_dev);
out1:
	return ret;
}
这一部分代码主要是实现input输入子系统的相关代码,注册和多点触摸相关的输入事件,之后要初始化了一个工作队列用来处理输入事件的上报操作,最后实现了和触摸屏相关的外部中断的注册通过它来检测触摸屏是按下还是松开。
4、处理多点触摸上报事件操作

当触摸屏被按下或者松开时,会触发对应的外部中断,这时候外部中断函数会被调用,外部中断函数实现如下:

/* 触摸屏触发时的中断处理程序 */
static irqreturn_t tiny4412_ts_interrupt(int irq, void *dev_id) 
{
	/* 通过工作队列唤醒内核线程来处理触摸相关事件 */
	schedule_work(&yl_tiny4412_ts.work_queue);
	return IRQ_HANDLED;
}
从上面可以看出,中断处理程序只是唤醒工作队列,让工作队列来处理具体和触摸相关的事件,这是因为IIC接口传输速度慢,会导致延时,而中断本身需要快速响应,所以直接在中断函数中处理触摸输入事件,会影响整个系统的性能。下面来看一下工作队列处理函数的具体实现:

/* 工作队列处理 */
static void tiny4412_work_queue_func(struct work_struct *work)
{
	int i;
	int ret;

	/* 读取触摸屏数据 */
	ret = tiny4412_ts_ft5x0x_read_data();
	if (ret < 0)	/* 触摸屏返回数据失败,直接返回 */
		return;

	/* 如果触摸屏松开 */
	if (!yl_tiny4412_ts.touch_points) {
		input_mt_sync(yl_tiny4412_ts.input_dev);
		input_sync(yl_tiny4412_ts.input_dev);
		return;
	}

	/* 如果触摸屏按下 */
	for (i = 0; i < yl_tiny4412_ts.touch_points; i++) { /* 每一个点 */
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_X, yl_tiny4412_ts.ts_event[i].x);
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_Y, yl_tiny4412_ts.ts_event[i].y);
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_TRACKING_ID, yl_tiny4412_ts.ts_event[i].id);
	    input_mt_sync(yl_tiny4412_ts.input_dev);	
	}
	input_sync(yl_tiny4412_ts.input_dev);
}
可以看出它通过调用tiny4412_ts_ft5x0x_read_data()这个函数来获取触摸点相关数据,然后来对触摸点事件进行上报,下面来看一看这个函数的具体实现:
static int tiny4412_ts_ft5x0x_read_data(void) {
	u8 buf[32] = { 0 };
	int ret;

	ret = tiny4412_ts_ft5x0x_i2c_rxdata(yl_tiny4412_ts.i2c_client, buf, 31);

	/* 读取触摸屏数据失败,返回负数 */
	if (ret < 0) {
		printk("%s: read touch data failed, %d\n", __func__, ret);
		return ret;
	}

	/* 获得当前触摸屏的触摸点数 */
	yl_tiny4412_ts.touch_points = buf[2] & 0x0f;

	switch (yl_tiny4412_ts.touch_points) {
		case 5:
			yl_tiny4412_ts.ts_event[4].x = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
			yl_tiny4412_ts.ts_event[4].y = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
			yl_tiny4412_ts.ts_event[4].id = buf[0x1d]>>4;
		case 4:
			yl_tiny4412_ts.ts_event[3].x = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
			yl_tiny4412_ts.ts_event[3].y = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
			yl_tiny4412_ts.ts_event[3].id = buf[0x17]>>4;
		case 3:
			yl_tiny4412_ts.ts_event[2].x = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
			yl_tiny4412_ts.ts_event[2].y = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
			yl_tiny4412_ts.ts_event[2].id = buf[0x11]>>4;
		case 2:
			yl_tiny4412_ts.ts_event[1].x = (s16)(buf[0x09] & 0x0F)<<8 | (s16)buf[0x0a];
			yl_tiny4412_ts.ts_event[1].y = (s16)(buf[0x0b] & 0x0F)<<8 | (s16)buf[0x0c];
			yl_tiny4412_ts.ts_event[1].id = buf[0x0b]>>4;
		case 1:
			yl_tiny4412_ts.ts_event[0].x = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];
			yl_tiny4412_ts.ts_event[0].y = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];
			yl_tiny4412_ts.ts_event[0].id = buf[0x05]>>4;
			break;
		case 0:	
			return 0;
		default:
			return -1;
	}

	return 0;
}
它又会调用tiny4412_ts_ft5x0x_i2c_rxdata()函数通过iic接口来取出触摸屏数据,然后首先获得触摸屏上的触摸点个数,然后通过计算发这些触摸点的数据放在事先定义好的数组中,那么tiny4412_ts_ft5x0x_i2c_rxdata()这个函数的具体实现是怎样的呢?如下所示:

static int tiny4412_ts_ft5x0x_i2c_rxdata(struct i2c_client *client, char *rxdata, int length) {
	int ret;
	struct i2c_msg msgs[] = {
		{
			.addr	= client->addr,
			.flags	= 0,
			.len	= 1,
			.buf	= rxdata,
		},
		{
			.addr	= client->addr,
			.flags	= I2C_M_RD,
			.len	= length,
			.buf	= rxdata,
		},
	};

	ret = i2c_transfer(client->adapter, msgs, 2);
	if (ret < 0)
		pr_err("%s: i2c read error: %d\n", __func__, ret);

	return ret;
}
从上面可以看出,它通过i2c_transfer()函数从触摸芯片当中读取触摸的原始数据。
以上多点触摸屏驱动程序就分析完毕了,文中难免有错误和不对的地方,请多多指教。

附录:完整的电容屏多点触摸驱动驱动完整代码

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>

#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/ctouch.h>
#include <plat/ft5x0x_touch.h>

/* 定义触摸驱动的名字 */
#define TINY4412_TS_NAME			"ft5x0x_ts"
#define TINY4412_TS_MAX_X  			800		// x轴最大分辨率
#define TINY4412_TS_MAX_Y  			480		// y轴最大分辨率
#define TINY4412_TS_MAX_ID 			10		// 由硬件来决定

/* 定义一个结构体用来描述触摸点的信息 */
struct yl_tiny4412_ts_event {
	int x;		// 获得的触摸点的x坐标
	int y;		// 获得的触摸点的y坐标
	int id;		// 获得触摸点的id,用来表示对应的触摸点
};

/* 定义一个全局结构体存放相关成员,更好的方便驱动程序的编写 */
struct yl_tiny4412_ts_config
{
	int gpio;						// 定义触摸屏外部中断的GPIO口
	int touch_points;				// 表示当前同时有几个触摸点或者说当前是几点触摸
	struct i2c_client *i2c_client;	// 用于存放i2c_client指针变量
	struct input_dev  *input_dev;	// 定义一个input_dev结构体指针变量
	struct work_struct work_queue;	// 定义工作队列,用来处理和触摸相关的事件
	struct yl_tiny4412_ts_event ts_event[10];	// 定义一个描述触摸点的数组 
};
/* 定义一个 yl_tiny4412_ts_config 结构体的全局变量 */
static struct yl_tiny4412_ts_config yl_tiny4412_ts;

static int tiny4412_ts_ft5x0x_i2c_rxdata(struct i2c_client *client, char *rxdata, int length) {
	int ret;
	struct i2c_msg msgs[] = {
		{
			.addr	= client->addr,
			.flags	= 0,
			.len	= 1,
			.buf	= rxdata,
		},
		{
			.addr	= client->addr,
			.flags	= I2C_M_RD,
			.len	= length,
			.buf	= rxdata,
		},
	};

	ret = i2c_transfer(client->adapter, msgs, 2);
	if (ret < 0)
		pr_err("%s: i2c read error: %d\n", __func__, ret);

	return ret;
}

static int tiny4412_ts_ft5x0x_read_data(void) {
	u8 buf[32] = { 0 };
	int ret;

	ret = tiny4412_ts_ft5x0x_i2c_rxdata(yl_tiny4412_ts.i2c_client, buf, 31);

	/* 读取触摸屏数据失败,返回负数 */
	if (ret < 0) {
		printk("%s: read touch data failed, %d\n", __func__, ret);
		return ret;
	}

	/* 获得当前触摸屏的触摸点数 */
	yl_tiny4412_ts.touch_points = buf[2] & 0x0f;

	switch (yl_tiny4412_ts.touch_points) {
		case 5:
			yl_tiny4412_ts.ts_event[4].x = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
			yl_tiny4412_ts.ts_event[4].y = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
			yl_tiny4412_ts.ts_event[4].id = buf[0x1d]>>4;
		case 4:
			yl_tiny4412_ts.ts_event[3].x = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
			yl_tiny4412_ts.ts_event[3].y = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
			yl_tiny4412_ts.ts_event[3].id = buf[0x17]>>4;
		case 3:
			yl_tiny4412_ts.ts_event[2].x = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
			yl_tiny4412_ts.ts_event[2].y = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
			yl_tiny4412_ts.ts_event[2].id = buf[0x11]>>4;
		case 2:
			yl_tiny4412_ts.ts_event[1].x = (s16)(buf[0x09] & 0x0F)<<8 | (s16)buf[0x0a];
			yl_tiny4412_ts.ts_event[1].y = (s16)(buf[0x0b] & 0x0F)<<8 | (s16)buf[0x0c];
			yl_tiny4412_ts.ts_event[1].id = buf[0x0b]>>4;
		case 1:
			yl_tiny4412_ts.ts_event[0].x = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];
			yl_tiny4412_ts.ts_event[0].y = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];
			yl_tiny4412_ts.ts_event[0].id = buf[0x05]>>4;
			break;
		case 0:	
			return 0;
		default:
			return -1;
	}

	return 0;
}


/* 工作队列处理 */
static void tiny4412_work_queue_func(struct work_struct *work)
{
	int i;
	int ret;

	/* 读取触摸屏数据 */
	ret = tiny4412_ts_ft5x0x_read_data();
	if (ret < 0)	/* 触摸屏返回数据失败,直接返回 */
		return;

	/* 如果触摸屏松开 */
	if (!yl_tiny4412_ts.touch_points) {
		input_mt_sync(yl_tiny4412_ts.input_dev);
		input_sync(yl_tiny4412_ts.input_dev);
		return;
	}

	/* 如果触摸屏按下 */
	for (i = 0; i < yl_tiny4412_ts.touch_points; i++) { /* 每一个点 */
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_X, yl_tiny4412_ts.ts_event[i].x);
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_Y, yl_tiny4412_ts.ts_event[i].y);
	    input_report_abs(yl_tiny4412_ts.input_dev, ABS_MT_TRACKING_ID, yl_tiny4412_ts.ts_event[i].id);
	    input_mt_sync(yl_tiny4412_ts.input_dev);	
	}
	input_sync(yl_tiny4412_ts.input_dev);
}

/* 触摸屏触发时的中断处理程序 */
static irqreturn_t tiny4412_ts_interrupt(int irq, void *dev_id) 
{
	/* 通过工作队列唤醒内核线程来处理触摸相关事件 */
	schedule_work(&yl_tiny4412_ts.work_queue);
	return IRQ_HANDLED;
}

/* 当驱动和设备匹配成功后会调用probe函数 */
static int tiny4412_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = 0;
	
	yl_tiny4412_ts.i2c_client = client;

	/* 1、分配一个input_dev的结构体指针变量 */
	yl_tiny4412_ts.input_dev= input_allocate_device();
	if (!(yl_tiny4412_ts.input_dev)) {
		printk("tiny4412_ts_probe->input_allocate_device error!\n");
		ret = -ENOMEM;
		goto out1;
	}

	/* 2、设置这个结构体变量 */
	/* 2.1 能产生哪类事件 */
	set_bit(EV_SYN, yl_tiny4412_ts.input_dev->evbit);	// 同步事件
	set_bit(EV_ABS, yl_tiny4412_ts.input_dev->evbit);	// 绝对位移类事件

	/* 2.2 能产生该类事件中哪些事件 */
	set_bit(ABS_MT_TRACKING_ID, yl_tiny4412_ts.input_dev->absbit);
	set_bit(ABS_MT_POSITION_X,  yl_tiny4412_ts.input_dev->absbit);
	set_bit(ABS_MT_POSITION_Y,  yl_tiny4412_ts.input_dev->absbit);

	/* 2.3 确定产生的这些事件的范围 */
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_TRACKING_ID, 0, TINY4412_TS_MAX_ID, 0, 0);
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_X, 0, TINY4412_TS_MAX_X, 0, 0);
	input_set_abs_params(yl_tiny4412_ts.input_dev, ABS_MT_POSITION_Y, 0, TINY4412_TS_MAX_Y, 0, 0);

	/* 2.4 其他设置 */
	set_bit(INPUT_PROP_DIRECT, yl_tiny4412_ts.input_dev->propbit); 
	yl_tiny4412_ts.input_dev->name = TINY4412_TS_NAME;	// Android系统会根据它找到配置文件

	/* 3、注册这个input_dev结构体指针变量 */
	ret = input_register_device(yl_tiny4412_ts.input_dev);
	if (ret)
	{
		printk("tiny4412_ts_probe->input_register_device error!\n");
		ret = -ENODEV;
		goto out2;
	}	
	
	/* 4、硬件相关的操作 */
	INIT_WORK(&yl_tiny4412_ts.work_queue, tiny4412_work_queue_func);	// 初始化工作队列

	ret = request_irq(gpio_to_irq(yl_tiny4412_ts.gpio), tiny4412_ts_interrupt,
			IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "tiny4412_ts", NULL);
	if (ret)
	{
		printk("tiny4412_ts_probe->request_irq error!\n");
		ret = -EIO;
		goto out3;
	}
	return 0;	// 一切正常则返回0
	
out3:
	input_unregister_device(yl_tiny4412_ts.input_dev);
out2:
	input_free_device(yl_tiny4412_ts.input_dev);
out1:
	return ret;
}

/* 当驱动和设备分离时会调用remove函数 */
static int __devexit tiny4412_ts_remove(struct i2c_client *client)
{
	free_irq(gpio_to_irq(yl_tiny4412_ts.gpio), NULL);
	input_unregister_device(yl_tiny4412_ts.input_dev);
	input_free_device(yl_tiny4412_ts.input_dev);
	cancel_work_sync(&yl_tiny4412_ts.work_queue);
	return 0;
}

/* 定义一个id表,用于i2c驱动和设备的匹配 */
static const struct i2c_device_id tiny4412_ts_id[] = {
	{ TINY4412_TS_NAME, 0 },
	{ }
};

/* 定义一个i2c_driver的实例 */
static struct i2c_driver tiny4412_ts_driver = {
	.probe		= tiny4412_ts_probe,
	.remove		= __devexit_p(tiny4412_ts_remove),
	.id_table	= tiny4412_ts_id,
	.driver	= {
		.name	= TINY4412_TS_NAME,
		.owner	= THIS_MODULE,
	},
};

/* 驱动的入口函数 */
static int __init tiny4412_ts_init(void)
{
	yl_tiny4412_ts.gpio = EXYNOS4_GPX1(6);	// 获得和触摸屏外部中断相关的GPIO口

	return i2c_add_driver(&tiny4412_ts_driver);
}

/* 驱动的出口函数 */
static void __exit tiny4412_ts_exit(void)
{
	i2c_del_driver(&tiny4412_ts_driver);
}

/* 对入口函数和出口函数进行修饰 */
module_init(tiny4412_ts_init);
module_exit(tiny4412_ts_exit);

/* 给驱动添加"GPL"协议 */
MODULE_LICENSE("GPL");

⑦tiny4412 Linux驱动开发之PWM驱动程序 这一次本来是准备讲解关于LCD亮度调节的,LCD调节用PWM的占空比来显示不同的亮度.然后看到网上EXYNOS4_GPD0(1)是连接到LCD的PWM接口的,可以通过这个调节亮度.但是到了我这,就变了,我这用的是1611的底板,LCD接口用的是LCD3,和上一篇一样,同样没有1611底板的电路图,网上暂时也没找到,就先用1506的电路图凑合着用了,然后1506的电路图没有LCD3接口,我就大概把L... 阅读详情

相关推荐

多点电容触摸驱动(基于gt911)

多点电容触摸的驱动使用到的知识主要有input子系统、gpio硬件中断、iic子系统,tslib测试等知识点,下面将针对多点电容触摸屏的驱动开发的四个知识点进行展开,以及gt911芯片的知识,官方gt9xx驱动的移植。

qq_50299271的博客 1万+

【TINY4412】LINUX移植笔记:(23)设备树LCD触摸屏驱动

【TINY4412】LINUX移植笔记:(23)设备树 LCD触摸屏驱动 宿主机 : 虚拟机 Ubuntu 16.04 LTS / X64 目标板[底板]: Tiny4412SDK - 1506 目标板[核心板]: Tiny4412 - 1412 LINUX内核: 4.12.0 交叉编译器: arm-none-linu

大水猫 4419

MT6260A参考原理图SCH和PCB

MT6260A的原理图和PCB文档,PADS版本的。

基于tiny210的四线触摸屏驱动修改(二)

接下来我们修改/drivers/input/touchscreen/ts-s3c.c,这个我是参考mini2440的触摸屏驱动进行修改的,可根据实际情况对红色代码部分进行修改。 #include #include #include #include #include #include #include #include #include #

armdesigner的专栏 1937

别再只飞不记了!用CsvView分析你的大疆飞行日志,优化航拍与排查炸机原因

本文详细介绍了如何利用CsvView工具分析大疆无人机的飞行日志,帮助用户优化航拍效率和飞行安全。通过解读飞行日志中的关键数据,如电池性能、飞行轨迹等,用户可以及时发现潜在问题并改进飞行习惯。文章还提供了事故排查方法和进阶分析技巧,适合无人机爱好者和专业飞手。

weixin_42535461的博客 547

DSPACE仿真平台的使用

DSPACE仿真平台的使用 文章目录DSPACE仿真平台的使用1.ModelDesk新建项目2.MotionDesk引入项目3.ControlDesk引入项目4.项目整合运行 我们使用DSPACE仿真平台软件来模拟小汽车的自动驾驶。 总共需要用到DSPACE大类下的三个软件:ModelDesk、ControlDesk、MotionDesk。 1.ModelDesk新建项目 在桌面上点击ModelDesk图标,打开DSPACE—ModelDesk 选择 File 标签,侧边栏选择 New,点击 New A

qq_42582489的博客 7526

tiny4412电容屏幕触摸屏驱动-ft5406芯片

准备开发tiny4412板子,也需要电容触摸屏ft5406 芯片,无意中看到下面这篇文章,很有参考价值,所以转载过来呵呵。原文地址 http://blog.youkuaiyun.com/gooogleman/article/details/7574591ft5406数据手册---------------------------------------------------------------------...

bo_的博客 1177

基于PSINS的INS/NHC/ODO组合导航仿真全解析

组合导航通过多传感器融合克服单一导航系统的局限,是车辆自主定位的关键技术。其中惯性导航(INS)依靠陀螺仪与加速度计积分推算运动状态,但误差随时间累积;GNSS提供绝对位置,却在城市峡谷中易受多径效应和遮挡影响导致定位漂移。卡尔曼滤波作为信息融合核心,将不同量测按统计特性加权,实现优势互补。基于PSINS开源工具箱搭建的SINS/GNSS/ODO/NHC组合导航仿真,能够在GNSS失锁条件下利用非完整约束和里程计抑制惯性误差发散,广泛应用于无人驾驶、物流车辆自主定位等场景。本文围绕PSINS仿真环境,详细拆

weixin_29044713的博客 252

Ft5406驱动

本文转自:http://blog.youkuaiyun.com/yunfly163/article/details/7388230 正确性无法保证,只为参考。或许那天我会重写Ft5406的驱动,那时候在看吧。。。 以下为原文。 最近刚调试好敦泰的电容触摸屏,现记录下。 -----------------------------------------------

Yasin Lee 3470

华硕笔记本+Ubuntu 20.04:用cpupower解决Intel CPU频率上不去/功耗墙问题实战

本文详细介绍了在华硕笔记本Ubuntu 20.04系统下使用cpupower工具解决Intel CPU频率受限和功耗墙问题的实战方法。通过禁用Intel P-State驱动、配置userspace模式以及高级调优技巧,帮助用户突破性能瓶颈,提升编译和计算效率。

weixin_42561476的博客 520

ABB机器人发送实时位置给PLC

本文使用中断方式实现,多任务要订购ABB功能包 Profinet总线组变量配置 注:映射为16位和32位均可用 声明数据 VAR num CurrentExAxisPos;!外轴位置 VAR robtarget pCurrentPos;!实时位置 var intnum TrapNum;!中断号 初始化开中断 IDelete TrapNum;!中断号 CONNECT TrapNum WITH iTrapCurPos;!连接中...

澍澍爸的blog 6775

设备树学习之(十三)电容触摸屏驱动

转载地址:https://blog.youkuaiyun.com/lizuobin2/article/details/55264211开发板:tiny4412SDK + S702 + 4GB Flash 要移植的内核版本:Linux-4.4.0 (支持device tree) u-boot版本:友善之臂自带的 U-Boot 2010.12 busybox版本:busybox 1.25友善之臂提供的资料中,触摸...

kunkliu的博客 999

tsmc12: m0po max length问题(H384.M0_PO.L.1)

手动调整可以挪cell,制造上下两个row相对的至少一个site的空间,通过插普通filler来解决,这里需要注意的是,tsmc12有via0的规则,需要让via0落在via0 grid上。在pt eco之后会有一些m0po max length问题出现,大部分问题都可以通过替换decap来解决,少部分由于局部density过高,需要手动调整。更多学习内容请关注「拾陆楼」知识星球。#ICC2中替换decap的参考脚本。

m0_61544122的博客 789

友善之臂编linux内核,手把手教你写Linux设备驱动---input子系统(四)--电容屏驱动ft5x06编写(一)(基于友善之臂4412开发板)...

这一节,我们将从零开始写tiny4412的触摸屏驱动ft5x06,写这节博客之前,先了解下需要什么知识:1、i2c驱动相关的知识2、输入子系统3、中断4、工作队列关于i2c驱动相关的知识,在后期的博文里会专门写几篇博文来进行总结,这里就不再说i2c相关的知识,我们先知道怎么用就行了。首先,我在ts.h构造了一个ts_info_st结构体,用来存放触摸屏的中断线,x坐标,y坐标,压力值。用ts_st...

weixin_30284477的博客 252

万字长文:YOLOv5+RK3588 NPU多线程加速全攻略——从理论到部署的终极优化

RK3588 NPU多线程加速优化教程摘要 本教程深入讲解了如何利用线程池技术优化RK3588 NPU上的YOLO目标检测模型推理性能。RK3588内置3个NPU核心,理论算力达6TOPS,为多线程优化提供了硬件基础。教程详细解析了线程池的核心组件(任务队列、工作线程、同步机制)和实现架构,包括类设计、初始化流程、工作线程逻辑(任务获取、NPU推理、结果存储三个阶段)以及任务提交/获取机制。通过预分配模型实例、线程绑定、流量控制等优化手段,实现了从单线程28FPS到多线程120FPS的显著性能提升,为边缘A

LXY_LOVE36的博客 1101

图解电动汽车:电动汽车电控系统

电动汽车的电控系统通常包含三个子控制系统 —— 整车控制器、电池管理系统、驱动电机控制器。 整车控制器 VCU 整车控制器 VCU(Vehicle Control Unit)作为电动汽车的中央控制单元,是整个控制系统的核心,也是各个子系统的调控中心。VCU 的主要功能就是协调管理整车的运行状态,包括采集电机及电池状态,采集加速踏板信号、制动踏板信号、执行器及传感器信号,根据驾驶员的意图综合分析做出相应判定后,监控下层的各部件控制器的动作,它负责汽车的正常行驶、制动能量回馈、整车发动机及动力电池的能量管理、.

程序员「阿基米东」的编程之旅 1万+

手把手教你写Linux设备驱动---input子系统(四)--电容屏驱动ft5x06编写(一)(基于友善之臂4412开发板)

这一节,我们将从零开始写tiny4412自带的触摸屏驱动法条ft5x06,写这节博客之前,先了解下需要什么知识:1、i2c驱动相关的知识2、输入子系统3、中断4、工作队列关于i2c驱动相关的知识,在后期的博文里会专门写几篇博文来进行总结,这里就不再说i2c相关的知识,我们先知道怎么用就行了。首先,我在ts.h构造了一个ts_info_st结构体,用来存放触摸屏的中断线,x坐标,y坐标,压力值。用t

Bruce.yang的嵌入式之旅 2898

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

手把手教你写Linux设备驱动---input子系统(四)--电容屏驱动ft5x06编写(一)(基于友善之臂4412开发板)...

这一节,我们将从零开始写tiny4412的触摸屏驱动ft5x06,写这节博客之前,先了解下需要什么知识: 1、i2c驱动相关的知识 2、输入子系统 3、中断 4、工作队列 关于i2c驱动相关的知识,在后期的博文里会专门写几篇博文来进行总结,这里就不再说i2c相关的知识,我们先知道怎么用就行了。 首先,我在ts.h构造了一个ts_info_st结构体,用来...

weixin_34417635的博客 328

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Tiny 4412 lcd 驱动分析 2

/home/yangjia/samba/linux-3.5/arch/arm/mach-exynos/mach-tiny4412.c  。_initdata 定义在此文件中。平台驱动都重要在这里注册。平台驱动是匹配名字的。 static struct platform_device *smdk4x12_devices[] __initdata = { #ifdef CONFIG_EXYNOS4_

xiaopohaibebo的专栏 3803

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Ft5x06_ts驱动程序的重写

我们分析内核源码可知,Ft5x06_ts触摸屏驱动程序涉及如下内容: 1.  Linux下I2C驱动框架 2.  Linux下中断系统 3.  Linux下workqueue机制 4.  Linux下输入子系统 5.  中断初始化、I2C控制器相关初始化。在arch/arm/mach-exynos/mach-smdk4x12.c中的s3c_i2c1_set_platdata(&tin

fengel_cs的专栏 4342

tiny4412 android控制板载LED

tiny4412 android控制板载LED 前言 这是我的tiny4412学习笔记,看的是韦东山老师的安卓四期视频,所以程序大体上都是跟韦东山老师的程序相同。 软件版本 Android Studio 4.1.3 Ubuntu 12.04(用的韦东山老师配置好的虚拟机) APP编写 这里的界面还算简单,就4个Checkbox和1个Button。所以直接上代码了。 MainActivity.java package com.example.app_0001_leddemo; import android

JAS-39D-ANM的博客 805

为Tiny4412设备驱动在proc目录下添加一个可读版本信息的文件

http://blog.youkuaiyun.com/morixinguan/article/details/77808088 上节,我们明白了proc文件系统的作用,接下来我们在友善之臂已经写好的led驱动的基础上,在proc目录下创建一个文件夹,然后加入led驱动的版本信息读取。 我们在init函数的最后加入: //定义proc文件系统节点 struct pr...

weixin_34355715的博客 171

linux驱动--多点触控协议(multi-touch-protocol)

Multi-touch-protocol Linux内核文档multi-touch-protocol.rst Introduction 为了充分利用新的多点触控和多用户设备的全部功能, 需要一种报告来自多个触点(即与设备表面直接接触的对象)的详细数据的方法。 此文档描述了允许内核驱动程序报告任意数量的触点的详细信息的多点触控协议。 根据硬件的能力,此协议被分为了两种类型。对于处理匿名触点的设备(type A), 此协议描述了如何将所有触点的原始数据发送给接收者。 对于能够跟踪可识别触点的设备,此协议描

weixin_43192805的博客 1654

10.2多点触摸屏驱动

配置信息:其中配置信息的byte1~4表示触摸屏尺寸:产品ID:触摸坐标:虽然一共有10组触摸点坐标寄存器组,但是它最多支持同时跟踪5个触摸点。

lf282481431的博客 2675
上一篇: 排序之五:快速排序(C语言实现)
下一篇: 堆栈的简单实现之一:基本操作(C语言实现)
TECH_PRO
博客等级 码龄10年 167粉丝 84原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值