最近项目上使用了一个GT1151,网上找了一圈,没有找到使用CTP模块开发的触摸驱动,楼主参考了一些帖子,弄了一个驱动,现在实现了基础单点触摸,楼主几乎没有这方面的开发经验,还有很多不足之处。
离线
设备树如下:
&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 = <®_aldo2>;*/
/*ctp_power_ldo = <®_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>;
离线
完整代码
#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 = ®data[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");
离线
还有个头文件
#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
离线