触摸屏驱动代码

本文主要介绍如何根据触摸屏厂商和型号编写驱动代码,虽然各型号间存在相似性。现在,我们将展示具体的驱动实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据TP的厂商和型号写相应的代码,不过大致都是差不多的,话不多说。
来吧!展示!上驱动代码:

/* drivers/input/touchscreen/gt9x.c*/
#include <linux/regulator/consumer.h>
#include "gt9xx.h"
#include <linux/of_gpio.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/input/mt.h>
#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/delay.h>

#define GOODIX_DEV_NAME	"Goodix-CTP"
#define CFG_MAX_TOUCH_POINTS	5
#define GOODIX_COORDS_ARR_SIZE	4
#define MAX_BUTTONS		4

#define CFG_GROUP_LEN(p_cfg_grp)  (sizeof(p_cfg_grp) / sizeof(p_cfg_grp[0]))

#define GOODIX_VTG_MIN_UV	2600000
#define GOODIX_VTG_MAX_UV	3300000
#define GOODIX_I2C_VTG_MIN_UV	1800000
#define GOODIX_I2C_VTG_MAX_UV	1800000
#define GOODIX_VDD_LOAD_MIN_UA	0
#define GOODIX_VDD_LOAD_MAX_UA	10000
#define GOODIX_VIO_LOAD_MIN_UA	0
#define GOODIX_VIO_LOAD_MAX_UA	10000

//#define RESET_DELAY_T3_US	200	/* T3: > 100us */
#define RESET_DELAY_T4		20	/* T4: > 5ms */

#define PHY_BUF_SIZE		32
#define PROP_NAME_SIZE		24

#define GTP_MAX_TOUCH		5
#define GTP_ESD_CHECK_CIRCLE_MS	2000

static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
static int gtp_i2c_test(struct i2c_client *client);
static int goodix_power_off(struct goodix_ts_data *ts);
static int goodix_power_on(struct goodix_ts_data *ts);

#if defined(CONFIG_FB)
static int fb_notifier_callback(struct notifier_block *self,
				unsigned long event, void *data);
static int goodix_ts_suspend(struct device *dev);
static int goodix_ts_resume(struct device *dev);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
#endif

#if GTP_ESD_PROTECT
static struct delayed_work gtp_esd_check_work;
static struct workqueue_struct *gtp_esd_check_workqueue;
static void gtp_esd_check_func(struct work_struct *work);
static int gtp_init_ext_watchdog(struct i2c_client *client);
#endif

enum doze {
   
	DOZE_DISABLED = 0,
	DOZE_ENABLED = 1,
	DOZE_WAKEUP = 2,
};
static enum doze doze_status = DOZE_DISABLED;
static s8 gtp_enter_doze(struct goodix_ts_data *ts);

bool init_done;
static u8 chip_gt9xxs;  /* true if ic is gt9xxs, like gt915s */
u8 grp_cfg_version;
struct i2c_client  *i2c_connect_client;

#define GTP_DEBUGFS_DIR			"ts_debug"
#define GTP_DEBUGFS_FILE_SUSPEND	"suspend"
#define GTP_DEBUGFS_FILE_DATA		"data"
#define GTP_DEBUGFS_FILE_ADDR		"addr"

/*******************************************************
Function:
	Read data from the i2c slave device.
Input:
	client:     i2c device.
	buf[0~1]:   read start address.
	buf[2~len-1]:   read data buffer.
	len:    GTP_ADDR_LENGTH + read bytes count
Output:
	numbers of i2c_msgs to transfer:
		2: succeed, otherwise: failed
*********************************************************/
int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
{
   
	struct goodix_ts_data *ts = i2c_get_clientdata(client);
	int ret = -EIO;
	u8 retries;
	struct i2c_msg msgs[2] = {
   
		{
   
			.flags	= !I2C_M_RD,
			.addr	= client->addr,
			.len	= GTP_ADDR_LENGTH,
			.buf	= &buf[0],
		},
		{
   
			.flags	= I2C_M_RD,
			.addr	= client->addr,
			.len	= len - GTP_ADDR_LENGTH,
			.buf	= &buf[GTP_ADDR_LENGTH],
		},
	};

	for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) {
   
		ret = i2c_transfer(client->adapter, msgs, 2);
		if (ret == 2)
			break;
//		dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
	}
	if (retries == GTP_I2C_RETRY_5) {
   
		dev_err(&client->dev, "I2C retry times: %d\n", GTP_I2C_RETRY_5);
		if (ts->pdata->slide_wakeup)
			/* reset chip would quit doze mode */
			if (DOZE_ENABLED == doze_status)
				return ret;

		if (init_done)
			gtp_reset_guitar(ts, 10);
		else
			dev_warn(&client->dev,
				"gtp_reset_guitar exit init_done=%d:\n",
				init_done);
	}
	return ret;
}

/*******************************************************
Function:
	Write data to the i2c slave device.
Input:
	client:     i2c device.
	buf[0~1]:   write start address.
	buf[2~len-1]:   data buffer
	len:    GTP_ADDR_LENGTH + write bytes count
Output:
	numbers of i2c_msgs to transfer:
	1: succeed, otherwise: failed
*********************************************************/
int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
{
   
	struct goodix_ts_data *ts = i2c_get_clientdata(client);
	int ret = -EIO;
	u8 retries;
	struct i2c_msg msg = {
   
		.flags = !I2C_M_RD,
		.addr = client->addr,
		.len = len,
		.buf = buf,
	};

	for (retries = 0; retries < GTP_I2C_RETRY_5; retries++) {
   
		ret = i2c_transfer(client->adapter, &msg, 1);
		if (ret == 1)
			break;
		dev_err(&client->dev, "I2C retry: %d\n", retries + 1);
	}
	if ((retries == GTP_I2C_RETRY_5)) {
   
		if (ts->pdata->slide_wakeup)
			if (DOZE_ENABLED == doze_status)
				return ret;

		if (init_done)
			gtp_reset_guitar(ts, 10);
		else
			dev_warn(&client->dev,
				"gtp_reset_guitar exit init_done=%d:\n",
				init_done);
	}
	return ret;
}

/*******************************************************
Function:
	i2c read twice, compare the results
Input:
	client:  i2c device
	addr:    operate address
	rxbuf:   read data to store, if compare successful
	len:     bytes to read
Output:
	FAIL:    read failed
	SUCCESS: read successful
*********************************************************/
int gtp_i2c_read_dbl_check(struct i2c_client *client,
			u16 addr, u8 *rxbuf, int len)
{
   
	u8 buf[16] = {
   0};
	u8 confirm_buf[16] = {
   0};
	u8 retry = 0;

	while (retry++ < GTP_I2C_RETRY_3) {
   
		memset(buf, 0xAA, 16);
		buf[0] = (u8)(addr >> 8);
		buf[1] = (u8)(addr & 0xFF);
		gtp_i2c_read(client, buf, len + 2);

		memset(confirm_buf, 0xAB, 16);
		confirm_buf[0] = (u8)(addr >> 8);
		confirm_buf[1] = (u8)(addr & 0xFF);
		gtp_i2c_read(client, confirm_buf, len + 2);

		if (!memcmp(buf, confirm_buf, len + 2))
			break;
	}
	if (retry < GTP_I2C_RETRY_3) {
   
		memcpy(rxbuf, confirm_buf + 2, len);
		return SUCCESS;
	} else {
   
		dev_err(&client->dev,
			"i2c read 0x%04X, %d bytes, double check failed!",
			addr, len);
		return FAIL;
	}
}

/*******************************************************
Function:
	Send config data.
Input:
	client: i2c device.
Output:
	result of i2c write operation.
	> 0: succeed, otherwise: failed
*********************************************************/
int gtp_send_cfg(struct goodix_ts_data *ts)
{
   
	int ret = 0;
	int retry;

	if (ts->pdata->driver_send_cfg) {
   
		if (ts->fixed_cfg) {
   
			dev_dbg(&ts->client->dev,
				"Ic fixed config, no config sent!");
			ret = 2;
		} else {
   
			for (retry = 0; retry < GTP_I2C_RETRY_5; retry++) {
   
				ret = gtp_i2c_write(ts->client,
					ts->config_data,
					GTP_CONFIG_MAX_LENGTH +
						GTP_ADDR_LENGTH);
				if (ret > 0)
					break;
			}
		}
	}

	return ret;
}

/*******************************************************
Function:
	Disable irq function
Input:
	ts: goodix i2c_client private data
Output:
	None.
*********************************************************/
void gtp_irq_disable(struct goodix_ts_data *ts)
{
   
	unsigned long irqflags;

	spin_lock_irqsave(&ts->irq_lock, irqflags);
	if (!ts->irq_is_disabled) {
   
		ts->irq_is_disabled = true;
		disable_irq_nosync(ts->client->irq);
	}
	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}

/*******************************************************
Function:
	Enable irq function
Input:
	ts: goodix i2c_client private data
Output:
	None.
*********************************************************/
void gtp_irq_enable(struct goodix_ts_data *ts)
{
   
	unsigned long irqflags = 0;

	spin_lock_irqsave(&ts->irq_lock, irqflags);
	if (ts->irq_is_disabled) {
   
		enable_irq(ts->client->irq);
		ts->irq_is_disabled = false;
	}
	spin_unlock_irqrestore(&ts->irq_lock, irqflags);
}

/*******************************************************
Function:
	Report touch point event
Input:
	ts: goodix i2c_client private data
	id: trackId
	x:  input x coordinate
	y:  input y coordinate
	w:  input pressure
Output:
	None.
*********************************************************/
static void gtp_touch_down(struct goodix_ts_data *ts, int id, int x, int y,
		int w)
{
   
	if (ts->pdata->change_x2y)
		swap(x, y);

	input_mt_slot(ts->input_dev, id);
	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
	input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
	input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
	input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
	input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
}

/*******************************************************
Function:
	Report touch release event
Input:
	ts: goodix i2c_client private data
Output:
	None.
*********************************************************/
static void gtp_touch_up(struct goodix_ts_data *ts, int id)
{
   
	input_mt_slot(ts->input_dev, id);
	input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
}



/*******************************************************
Function:
	Goodix touchscreen work function
Input:
	work: work struct of goodix_workqueue
Output:
	None.
*********************************************************/
static void goodix_ts_work_func(struct work_struct *work)
{
   
	u8 end_cmd[3] = {
    GTP_READ_COOR_ADDR >> 8,
			GTP_READ_COOR_ADDR & 0xFF, 0};
	u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {
   
			GTP_READ_COOR_ADDR >> 8,
			GTP_READ_COOR_ADDR & 0xFF};
	u8 touch_num = 0;
	u8 finger = 0;
	static u16 pre_touch;
	static u8 pre_key;
	static u8 pre_pen;
	u8 key_value = 0;
	u8 *coor_data = NULL;
	s32 input_x = 0;
	s32 input_y = 0;
	s32 input_w = 0;
	s32 id = 0;
	s32 i = 0;
	int ret = -1;
	struct goodix_ts_data *ts = NULL;
	u8 doze_buf[3] = {
   0x81, 0x4B};

	ts = container_of(work, struct goodix_ts_data, work);
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
	if (ts->enter_update)
		return;
#endif

	if (ts->pdata->slide_wakeup) {
   
		if (DOZE_ENABLED == doze_status) {
   
			ret = gtp_i2c_read(ts->client, doze_buf, 3);
			if (ret > 0) {
   
				if (doze_buf[2] == 0xAA) {
   
					dev_dbg(&ts->client->dev,
						"Slide(0xAA) To Light up the screen!");
					doze_status = DOZE_WAKEUP;
					input_report_key(
						ts->input_dev, KEY_POWER, 1);
					input_sync(ts->input_dev);
					input_report_key(
						ts->input_dev, KEY_POWER, 0);
					input_sync(ts->input_dev);
					/* clear 0x814B */
					doze_buf[2] = 0x00;
					gtp_i2c_write(ts->client, doze_buf, 3);
				} else if (doze_buf[2] == 0xBB) {
   
					dev_dbg(&ts->client->dev,
						"Slide(0xBB) To Light up the screen!");
					doze_status = DOZE_WAKEUP;
					input_report_key(ts->input_dev,
								KEY_POWER, 1);
					input_sync(ts->input_dev);
					input_report_key(ts->input_dev,
								KEY_POWER, 0);
					input_sync(ts->input_dev);
					/* clear 0x814B*/
					doze_buf[2] = 0x00;
					gtp_i2c_write(ts->client, doze_buf, 3);
				} else if (0xC0 == (doze_buf[2] & 0xC0)) {
   
					dev_dbg(&ts->client->dev,
						"double click to light up the screen!");
					doze_status = DOZE_WAKEUP;
					input_report_key(ts->input_dev,
								KEY_POWER, 1);
					input_sync(ts->input_dev);
					input_report_key(ts->input_dev,
								KEY_POWER, 0);
					input_sync(ts->input_dev);
					/* clear 0x814B */
					doze_buf[2] = 0x00;
					gtp_i2c_write(ts->client, doze_buf, 3);
				} else {
   
					gtp_enter_doze(ts);
				}
			}
			if (ts->use_irq)
				gtp_irq_enable(ts);

			return;
		}
	}

	ret = gtp_i2c_read(ts->client, point_data, 12);
	if (ret < 0) {
   
		dev_err(&ts->client->dev,
				"I2C transfer error. errno:%d\n ", ret);
		goto exit_work_func;
	}

	finger = point_data[GTP_ADDR_LENGTH];
	if ((finger & 0x80) == 0)
		goto exit_work_func;

	touch_num = finger & 0x0f;
	if (touch_num > GTP_MAX_TOUCH)
		goto exit_work_func;

	if (touch_num > 1) {
   
		u8 buf[8 * GTP_MAX_TOUCH] = {
    (GTP_READ_COOR_ADDR + 10) >> 8,
				(GTP_READ_COOR_ADDR + 10) & 0xff };

		ret = gtp_i2c_read(ts->client, buf,
				2 + 8 * (touch_num - 1));
		memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
	}


	key_value = point_data[3 + 8 * touch_num];

	if (key_value || pre_key) {
   
		for (i = 0; i < ts->pdata->num_button; i++) {
   
			input_report_key(ts->input_dev,
				ts->pdata->button_map[i],
				key_value & (0x01<<i));
		}
		touch_num = 0;
		pre_touch = 0;
	}

	pre_key = key_value;

	if (ts->pdata->with_pen) {
   
		if (pre_pen && (touch_num == 0)) {
   
			dev_dbg(&ts->client->dev, "Pen touch UP(Slot)!");
			input_report_key(ts->input_dev, BTN_TOOL_PEN, 0);
			input_mt_slot(ts->input_dev, 5);
			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
			pre_pen = 0;
		}
	}

	if (pre_touch || touch_num) {
   
		s32 pos = 0;
		u16 touch_index = 0;

		coor_data = &point_data[3];
		if (touch_num) {
   
			id = coor_data[pos] & 0x0F;
			if (ts->pdata->with_pen) {
   
				id = coor_data[pos];
				if (id == 128) {
   
					dev_dbg(&ts->client->dev,
							"Pen touch DOWN(Slot)!");
					input_x  = coor_data[pos + 1]
						| (coor_data[pos + 2] << 8);
					input_y  = coor_data[pos + 3]
						| (coor_data[pos + 4] << 8);
					input_w  = coor_data[pos + 5]
						| (coor_data[pos + 6] << 8);

					input_report_key(ts->input_dev,
						BTN_TOOL_PEN, 1);
					input_mt_slot(ts->input_dev, 5);
					input_report_abs(ts->input_dev,
						ABS_MT_TRACKING_ID, 5);
					input_report_abs(ts->input_dev,
						ABS_MT_POSITION_X, input_x);
					input_report_abs(ts->input_dev,
						ABS_MT_POSITION_Y, input_y);
					input_report_abs(ts->input_dev,
						ABS_MT_TOUCH_MAJOR, input_w);
					dev_dbg(&ts->client->dev,
						"Pen/Stylus: (%d, %d)[%d]",
						input_x, input_y, input_w);
					pre_pen = 1;
					pre_touch = 0;
				}
			}

			touch_index |= (0x01<<id);
		}

		for (i = 0; i < GTP_MAX_TOUCH; i++) {
   
			if (ts->pdata->with_pen)
				if (pre_pen == 1)
					break;

			if (touch_index & (0x01<<i)) {
   
				input_x = coor_data[pos + 1] |
						coor_data[pos + 2] << 8;
				input_y = coor_data[pos + 3] |
						coor_data[pos + 4] << 8;
				input_w = coor_data[pos + 5] |
						coor_data[pos + 6] << 8;

				gtp_touch_down(ts, id,
						input_x, input_y, input_w);
				pre_touch |= 0x01 << i;

				pos += 8;
				id = coor_data[pos] & 0x0F;
				touch_index |= (0x01<<id);
			} else {
   
				gtp_touch_up(ts, i);
				pre_touch &= ~(0x01 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值