您尚未登录。

楼主 # 昨天 09:32:03

上邪
会员
注册时间: 2022-02-15
已发帖子: 48
积分: 83

分享一个GT115触摸驱动

最近项目上使用了一个GT1151,网上找了一圈,没有找到使用CTP模块开发的触摸驱动,楼主参考了一些帖子,弄了一个驱动,现在实现了基础单点触摸,楼主几乎没有这方面的开发经验,还有很多不足之处。

离线

楼主 #1 昨天 09:36:24

上邪
会员
注册时间: 2022-02-15
已发帖子: 48
积分: 83

Re: 分享一个GT115触摸驱动

设备树如下:

&twi2 {
	clock-frequency = <400000>;
	pinctrl-0 = <&twi2_pins_a>;
	pinctrl-1 = <&twi2_pins_b>;
	pinctrl-names = "default", "sleep";
	/* For stability and backwards compatibility, we recommend setting ‘twi_drv_used’ to 0  */
	twi_drv_used = <0>;
	twi_pkt_interval = <0>;
	status = "okay";

	ctp@14 {
		compatible = "allwinner,goodix";
		device_type = "ctp";
		reg = <0x14>;
		ctp_name = "gt1xx_ts";
		ctp_twi_id = <0x2>;
		ctp_twi_addr = <0x14>;
		ctp_screen_max_x = <0x320>;
		ctp_screen_max_y = <0x1e0>;
		ctp_revert_x_flag = <0x0>;
		ctp_revert_y_flag = <0x0>;
		ctp_exchange_x_y_flag = <0x0>;
		ctp_int_port = <&pio PD 8 14 0x1 0x2 0>;
		ctp_wakeup = <&pio PF 5 1 0x1 0x2 0>;
		/*ctp-supply = <&reg_aldo2>;*/
		/*ctp_power_ldo = <&reg_aldo2>;*/
		/*ctp_power_ldo_vol = <3300>;*/
		status = "okay";
	};
};

这几个参数驱动里面现在没用到,宽高在驱动里面固定了的

ctp_screen_max_x = <0x320>;
ctp_screen_max_y = <0x1e0>;
ctp_revert_x_flag = <0x0>;
ctp_revert_y_flag = <0x0>;
ctp_exchange_x_y_flag = <0x0>;

离线

楼主 #2 昨天 09:38:43

上邪
会员
注册时间: 2022-02-15
已发帖子: 48
积分: 83

Re: 分享一个GT115触摸驱动

完整代码

#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include "../../init-input.h"
#include <linux/input/mt.h>
#include <linux/gpio.h>

#include "gt1xx.h"

static struct ctp_config_info config_info;
static struct workqueue_struct *goodix_wq=NULL;
static struct work_struct work;
static struct input_dev *input=NULL;
static struct i2c_client *ts_i2c_client=NULL;

static void ctp_print_config(struct ctp_config_info *info)
{   
	printk("info->ctp_used:%d\n",info->ctp_used);
	printk("info->twi_id:%d\n",info->twi_id);
	printk("info->screen_max_x:%d\n",info->screen_max_x);
	printk("info->screen_max_y:%d\n",info->screen_max_y);
	printk("info->revert_x_flag:%d\n",info->revert_x_flag);
	printk("info->revert_y_flag:%d\n",info->revert_y_flag);
	printk("info->exchange_x_y_flag:%d\n",info->exchange_x_y_flag);
	printk("info->irq_gpio_number:%d\n",info->irq_gpio.gpio);
	printk("info->wakeup_gpio_number:%d\n",info->wakeup_gpio.gpio);
}

static int goodix_ts_init(void)
{
    int ret = -1;
    int val = 0;
    struct device_node *np = NULL;

	memset(&config_info,0,sizeof(struct ctp_config_info));
	config_info.input_type = CTP_TYPE,
	config_info.name = NULL,
	config_info.int_number = 0,

    printk("GTP driver init\n");
	ret=input_sensor_startup(&(config_info.input_type));
	if (ret==0)
	{
		ret = input_sensor_init(&(config_info.input_type));
		if (ret != 0)
		{
			pr_err("%s:ctp_ops.input_sensor_init err.\n", __func__);
			return ret;
		}
		input_set_power_enable(&(config_info.input_type), 1);
	}
	else
	{
		pr_err("%s: input_ctp_startup err.\n", __func__);
		return 0;
	}

    if(config_info.ctp_used == 0)
	{
		printk("*** ctp_used set to 0 !\n");
		printk("*** if use ctp,please put the sys_config.fex ctp_used set to 1. \n");
		return 0;
	}

	np = of_find_node_by_name(NULL, "ctp");
	if (!np)
	{
		pr_err("ERROR! get ctp node failed, func:%s, line:%d\n",__FUNCTION__, __LINE__);
		return -1;
	}

	ret = of_property_read_u32(np, "ctp_gesture_wakeup", &val);
	if (ret) 
	{
		pr_err("get ctp_gesture_wakeup is fail, %d\n", ret);
	}
    msleep(10);

	ctp_print_config(&config_info);

    // sunxi_gpio_to_name(config_info.int_number,irq_pin_name);
    // gtp_io_init(20);

    goodix_wq = create_singlethread_workqueue("goodix_wq");
    if (goodix_wq==NULL)
    {
		printk("Creat workqueue failed.");
		return -ENOMEM;
    }
    
    return 0;
}

// 从GT1151读取多个寄存器数据
static int gt1151_read_regs(struct i2c_client *client, unsigned short reg,unsigned char *buf, int len)
{
	int ret;
    unsigned char regdata[2];
	struct i2c_msg msg[2];
    
    /* GT1151寄存器长度为2个字节 */
    regdata[0] = reg >> 8;
    regdata[1] = reg & 0xFF;
 
	// 别和SPI通信方式搞混了
	/* msg[0]为发送要读取的首地址 */
	msg[0].addr = client->addr;			/* gt1151地址 应该是设备树中的器件地址 */
	msg[0].flags = !I2C_M_RD;			/* 标记为发送数据 */
	msg[0].buf = &regdata[0];			/* 读取的首地址 */
	msg[0].len = 2;						/* reg长度*/
 
	/* msg[1]读取数据 */
	msg[1].addr = client->addr;			/* gt1151地址 */
	msg[1].flags = I2C_M_RD;			/* 标记为读取数据*/
	msg[1].buf = buf;					/* 读取数据缓冲区 */
	msg[1].len = len;					/* 要读取的数据长度*/
 
	ret = i2c_transfer(client->adapter, msg, 2);
	if(ret == 2) {
		ret = 0;
	} else {
		ret = -EREMOTEIO;
	}
	return ret;
}
 
// 向GT1151多个寄存器写入数据
static unsigned int gt1151_write_regs(struct i2c_client *client,unsigned short reg, unsigned char *buf,int len)
{
	unsigned char b[256];
	struct i2c_msg msg;
	
	b[0] = reg >> 8;			/* 寄存器首地址低8位 */
    b[1] = reg & 0XFF;			/* 寄存器首地址高8位 */
	memcpy(&b[2],buf,len);		/* 将要写入的数据拷贝到数组b里面 */
 
	msg.addr = client->addr;	/* gt1151地址 */
	msg.flags = 0;				/* 标记为写数据 */
 
	msg.buf = b;				/* 要写入的数据缓冲区 */
	msg.len = len + 2;			/* 要写入的数据长度 */
 
	return i2c_transfer(client->adapter, &msg, 1);
}

// GT1151读取固件
static int gt1151_read_firmware(struct i2c_client *client)
{
	int ret = 0, version = 0;
	unsigned short id = 0;
	unsigned char data[7]={0};
	char id_str[5];
	int max_x =0,max_y=0,irqtype=0;

	ret = gt1151_read_regs(client, GT_PID_REG, data, 6);
	if (ret) 
	{
		dev_err(&client->dev, "Unable to read PID.\n");
		return ret;
	}
	memcpy(id_str, data, 4);
	id_str[4] = 0;
 
    if (kstrtou16(id_str, 10, &id))id = 0x1001;
 
	version=data[5]<<1|data[4];
	
	dev_info(&client->dev, "ID %d, version: %04x\n", id, version);
	switch (id)
	{    /* 由于不同的芯片配置寄存器地址不一样需要判断一下  */
		case 1151:
		case 1158:
		case 5663:
		case 5688:    /* 读取固件里面的配置信息  */
			ret = gt1151_read_regs(client, GT_1xx_CFGS_REG, data, 7);  
			break;
		default:
			ret = gt1151_read_regs(client, GT_1xx_CFGS_REG, data, 7);
			break;
    }

	if (ret)
	{
		dev_err(&client->dev, "Unable to read Firmware.\n");
		return ret;
	}

	max_x=(data[2] << 8) + data[1];
	max_y = (data[4] << 8) + data[3];
	irqtype = data[6] & 0x3;
	printk("X_MAX: %d, Y_MAX: %d, TRIGGER: 0x%02x\r\n", max_x, max_y, irqtype);
 
	return 0;
}

static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
	input_set_int_enable(&(config_info.input_type), 0);
	queue_work(goodix_wq,&work);
	return IRQ_HANDLED;
}

static void goodix_ts_work_func(struct work_struct *work)
{
	int touch_num = 0;
    int input_x, input_y;
    int id = 0;
    int ret = 0;
    unsigned char data;
    unsigned char touch_data[5];
    struct i2c_client *client = ts_i2c_client;
 
	// printk("%s\r\n",__func__);

	if(client==NULL)
	{
		return;
	}
	
    ret = gt1151_read_regs(client, GT_GSTID_REG, &data, 1);// GT1151当前检测到的触摸情况
	/* 没有触摸数据,直接返回 */
    if (data == 0x00) 
	{
		printk("GT_GSTID_REG=%d\r\n",ret);
		goto exit;
    } 
	else
	{                 /* 统计触摸点数据 */
        touch_num = data & 0x0f;
    }
 
    /* 由于GT1151没有硬件检测每个触摸点按下和抬起,因此每个触摸点的抬起和按
     * 下不好处理,尝试过一些方法,但是效果都不好,因此这里暂时使用单点触摸 
     */

	// printk("touch_num=%d\r\n",touch_num);
    if(touch_num)
	{         /* 单点触摸按下 */
        gt1151_read_regs(client, GT_TP1_REG, touch_data, 5);
        id = touch_data[0] & 0x0F;

		// printk("id=%d\r\n",id);
        if(id == 0)
		{
            // input_x  = touch_data[1] | (touch_data[2] << 8);
            // input_y  = touch_data[3] | (touch_data[4] << 8);
			input_y = touch_data[1] | (touch_data[2] << 8);
            input_x = touch_data[3] | (touch_data[4] << 8);
			input_y=640-input_y;
			input_x=480-input_x;
			// 单点id一直等于0即可
            input_mt_slot(input, 0);
		    input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
		    input_report_abs(input, ABS_MT_POSITION_X, input_x);
		    input_report_abs(input, ABS_MT_POSITION_Y, input_y);

			printk("input_x=%d input_y=%d\r\n",input_x,input_y);
        }
    } 
	else if(touch_num == 0)
	{                /* 单点触摸释放 */
        input_mt_slot(input, id);
        input_mt_report_slot_state(input, MT_TOOL_FINGER, false);// 删除触摸点
    }
 
	input_mt_report_pointer_emulation(input, true);// 没有出现硬件检测到的点比上报的触摸点多的情况
    input_sync(input);
 
    data = 0x00;                /* 向0X814E寄存器写0 */
    gt1151_write_regs(client, GT_GSTID_REG, &data, 1);

	exit:
	input_set_int_enable(&(config_info.input_type), 1);
}

static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret=0;
	unsigned char data;

	printk("%s\r\n",__func__);
	ret=goodix_ts_init();
	if(ret!=0)
	{
		return -1;
	}
	config_info.dev = &client->dev;
	ts_i2c_client=client;
	printk("goodix_ts_init:%d\r\n",ret);

	//硬件复位
	gpio_set_value(config_info.wakeup_gpio.gpio, 0); /* 复位GT1151 */
    msleep(10);
 
    gpio_set_value(config_info.wakeup_gpio.gpio, 1); /* 停止复位GT1151 */
    msleep(100);

	/* 3,初始化GT1151 */
    data= 0x02;
    ret=gt1151_write_regs(client, GT_CTRL_REG, &data, 1); /* 软复位 */
	printk("gt1151 start reset %d\r\n",ret);
    msleep(100);
    data = 0x0;
    ret=gt1151_write_regs(client, GT_CTRL_REG, &data, 1); /* 停止软复位 */
	printk("gt1151 stop reset %d\r\n",ret);
    msleep(100);

	/* 4,初始化GT1151,读触摸设备的信息*/
	ret=gt1151_read_firmware(client);
	if(ret!=0)
	{
		return -1;
	}

	/* 5,input设备注册 */
	input= devm_input_allocate_device(&client->dev);
	if (input==NULL)
	{
		printk("%s:devm_input_allocate_device fail.\r\n",__func__);
		return -ENOMEM;
	}
	input->name = client->name;
	input->id.bustype = BUS_I2C;
	input->dev.parent = &client->dev;
 
	__set_bit(EV_KEY, input->evbit);
	__set_bit(EV_ABS, input->evbit);
	__set_bit(BTN_TOUCH, input->keybit);
 
	input_set_abs_params(input, ABS_X, 0,480, 0, 0);
	input_set_abs_params(input, ABS_Y, 0,640 , 0, 0);
	input_set_abs_params(input, ABS_MT_POSITION_X,0,480, 0, 0);
	input_set_abs_params(input, ABS_MT_POSITION_Y,0,640, 0, 0);	     
	ret = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
	if (ret) 
	{
		printk("input_mt_init_slots:%d\r\n",ret);
		return ret;
	}
 
	ret = input_register_device(input);
	if (ret)
	{
		printk("input_register_device:%d\r\n",ret);
		return ret;
	}

	INIT_WORK(&work, goodix_ts_work_func);

	ret=input_request_int(&(config_info.input_type), goodix_ts_irq_handler,IRQF_TRIGGER_FALLING,client);
	if(ret!=0)
	{
		printk("input_request_int:%d\r\n",ret);
		return ret;
	}
	return 0;
}

static int goodix_ts_remove(struct i2c_client *client)
{
	printk("%s\r\n",__func__);
	// i2c_del_driver(&goodix_ts_driver);
	if(input!=NULL)
	{
		input_unregister_device(input);
	}
    if (goodix_wq!=NULL)
    {
        destroy_workqueue(goodix_wq);
    }
	input_sensor_free(&(config_info.input_type));
	return 0;
}

static const struct i2c_device_id goodix_ts_id[] =
{
	{ "gt1xx_ts", 0 },
	{ }
};

static const struct of_device_id goodix_ts_match[] =
{
    { .compatible = "allwinner,goodix" },
};
static struct i2c_driver goodix_ts_driver = 
{
	.class          = I2C_CLASS_HWMON,
	.probe          = goodix_ts_probe,
	.remove         = goodix_ts_remove,
	.id_table       = goodix_ts_id,
	.driver = {
		.name   = "gt1xx_ts",
		.owner  = THIS_MODULE,
		.of_match_table =goodix_ts_match,
	},
};

module_i2c_driver(goodix_ts_driver);

MODULE_DESCRIPTION("GTP Series Driver");
MODULE_LICENSE("GPL");

离线

楼主 #3 昨天 09:41:12

上邪
会员
注册时间: 2022-02-15
已发帖子: 48
积分: 83

Re: 分享一个GT115触摸驱动

还有个头文件

#ifndef _GT_1XX_H_
#define _GT_1XX_H_

#ifdef __cplusplus
extern "C" {
#endif

#define GT_CTRL_REG 	        0X8040  /* GT1151控制寄存器         */
#define GT_MODSW_REG 	        0X804D  /* GT1151模式切换寄存器        */
#define GT_9xx_CFGS_REG 	    0X8047  /* GT1151配置起始地址寄存器    */
#define GT_1xx_CFGS_REG 	    0X8050  /* GT1151配置起始地址寄存器    */
#define GT_CHECK_REG 	        0X80FF  /* GT1151校验和寄存器       */
#define GT_PID_REG 		        0X8140  /* GT1151产品ID寄存器       */
 
#define GT_GSTID_REG 	        0X814E  /* GT1151当前检测到的触摸情况 */
#define GT_TP1_REG 		        0X814F  /* 第一个触摸点数据地址 */
#define GT_TP2_REG 		        0X8157	/* 第二个触摸点数据地址 */
#define GT_TP3_REG 		        0X815F  /* 第三个触摸点数据地址 */
#define GT_TP4_REG 		        0X8167  /* 第四个触摸点数据地址  */
#define GT_TP5_REG 		        0X816F	/* 第五个触摸点数据地址   */
#define MAX_SUPPORT_POINTS      5       /* 最多5点电容触摸 */

struct gt1xx_dev
{
    struct input_dev input;
    struct ctp_config_info info;
    struct i2c_client *client;
};


#ifdef __cplusplus
}
#endif

#endif

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn