基于imx6芯片,Linux系统的touch驱动移植,IC是GOODIX GA657X
参考:https://blog.csdn.net/zhaoxiaoqiang10_/article/details/24009889
硬件部分:其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分:
1、IIC部分,初始化gt657x的数据和传回主控制的坐标位置信息就是通过IIC这条线传输的;
2、INT,当gt657x初触摸时,会发出中断通知主控接收信息(坐标数据);
3、gt657x电源、复位这一部分,不同芯片有所不同,可以根据触摸屏芯片来配置
软件部分:
配置iic,在设备树中添加ga657x的配置信息,包括设备地址、ping脚定义、参数配置
ga657x@5d {
compatible = "goodix,ga657x";
reg = <0x5d>; //设备地址
status = "okay";
// pinctrl-names = "default";
// pinctrl-0 = <&ts_int_default>;
reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; //reset管脚
tp-irq-gpio = <&gpio4 10 GPIO_ACTIVE_LOW>; //中断脚
irq-flags = <2>;
touchscreen-max-id = <5>;
touchscreen-size-x = <1279>; //触摸屏的分辨率大小
touchscreen-size-y = <719>;
touchscreen-max-w = <255>;
touchscreen-max-p = <255>;
touchscreen-key-map = <50>, <35>, <103>, <108>; //按键地址
goodix,slide-wakeup = <0>;
goodix,type-a-report = <0>;
goodix,driver-send-cfg = <1>; //根据需求配置,1 会将驱动中的touch配置更新到固件中,0 则默认使用固件中刷写的配置
goodix,resume-in-workqueue = <0>;
goodix,swap-x2y = <0>;
goodix,esd-protect = <0>;
goodix,auto-update = <0>;
goodix,auto-update-cfg = <0>;
goodix,power-off-sleep = <0>;
goodix,pen-suppress-finger = <0>;
goodix,cfg-group2 = [
42 65 1B 1D 24 18 00 3B 52 9C 96 00 1E 50 3C 00 00 17 19 1C 14 22 FF 1E 78 00 00 0F 11 5E 22 22 F4 00 00 00 F0 00 05 D0 02 12 11 AA 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 14 15 16 17 18 19 1A 1B 1C 1D 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 27 FF FF FF FF FF 00 19 2D 94 C1 52 0A 04 B4 B4 1B 9C 9C 26 80 80 2D 00 76 76 00 00 00 00 00 00 02 00 D4 04 5C 46 32 20 AA 02 27 12 10 8E 8C BF BF BF BF BF BF 02 14 03 2D 23 AF 05 0F 28 06 81 28 14 1E 3C A0 6F 64 28 00 00 24 01
]; //配置信息,不同的屏配置不同,需要原厂提供适配的cfg
};
移植代码,并修改上一级目录的Makefile和Kconfig文件,因为原厂提供的驱动代码已经将makefile和Kconfig写好,所以移植时,只需要将适配到我们自己的目录环境中添加编译
Kconfig:
source "drivers/input/touchscreen/ga657x/Kconfig"
Makefile
obj-$(CONFIG_TOUCHSCREEN_GA657X) += ga657x/
配置内核,打开ga657x的配置选项,参与编译
│ Symbol: TOUCHSCREEN_GA657X [=y] │
│ Type : boolean │
│ Prompt: Goodix touchpanel GA657X series │
│ Location: │
│ -> Device Drivers │
│ -> Input device support │
│ -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) │
│ (1) -> Touchscreens (INPUT_TOUCHSCREEN [=y]) │
│ Defined at drivers/input/touchscreen/ga657x/Kconfig:4 │
│ Depends on: !UML && INPUT [=y] && INPUT_TOUCHSCREEN [=y] && I2C [=y]
以上配置完成可以进行下一步调试,重新刷写编译完成的kernel,确保硬件连接正常,开机后应该就可以在/dev/input/下发现设备节点
使用evtest工具测试,一般就可以测试触摸事件了: evtest /dev/input/event0
点击触屏,界面还是没有反应,可能是触屏里没有烧录配置文件或者配置文件不对,所以联系触屏(所使用的屏幕和液晶、触屏组合屏)厂家了解情况和获取配置文件,或者是IIC等ping脚配置错误,需要结合原理图分析。
在GA657x的代码中,原厂已经增加了上电开短路自测的功能,需要把接口映射出来给EOL测试。
总体流程如下:
下发自检命令,读取自检结果-》复位IC-》读取自诊断结果
#ifdef SELF_TEST_ENABLE
static int current_self_test_status = 1;
static int current_self_result = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
static int current_self_result_oc = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
struct goodix_ts_data *Self_ts;
/*******************************************************
* Function:
* Short current test result get //获取短路测试自检结果
* Input:
* ts: goodix tp private data
* Output:
* .
*********************************************************/
static int gtp_sc_handler(struct goodix_ts_data *ts)
{
u8 doze_buf[3] = {GTP_REG_SC_TEST_STATE >> 8, GTP_REG_SC_TEST_STATE & 0xFF};
int ret;
dev_info(&ts->client->dev, "enter gtp_sc_handler\n");
ret = gtp_i2c_read(ts->client, doze_buf, 3);
if (ret < 0) {
dev_err(&ts->client->dev, "Failed read doze buf");
current_self_result = GTP_ERROR_TIMEOUT;
return -EINVAL;
}
if(doze_buf[2] == 0x88){
doze_buf[0] = GTP_REG_SC_TEST_RESULT >> 8;
doze_buf[1] = GTP_REG_SC_TEST_RESULT & 0xff;
dev_info(&ts->client->dev, "Short current test complete\n");
}
else{
int i = 5;
while(i--){
/* Write for a moment */
usleep_range(10000,11000);
doze_buf[0] = GTP_REG_SC_TEST_STATE >> 8;
doze_buf[1] = GTP_REG_SC_TEST_STATE & 0xff;
ret = gtp_i2c_read(ts->client, doze_buf, 3);
if (ret < 0) {
dev_err(&ts->client->dev, "Failed read doze buf");
current_self_result = GTP_ERROR_TIMEOUT;
return -EINVAL;
}
if(doze_buf[2] == 0x88){
doze_buf[0] = GTP_REG_SC_TEST_RESULT >> 8;
doze_buf[1] = GTP_REG_SC_TEST_RESULT & 0xff;
break;
}
else{
dev_err(&ts->client->dev, "Short current test state is %02x\n",doze_buf[2]);
}
}
if(i == 0){
current_self_result = GTP_ERROR_TIMEOUT;
dev_err(&ts->client->dev, "sc error code %d\n",doze_buf[2]);
return -EINVAL;
}
}
ret = gtp_i2c_read(ts->client, doze_buf, 3);
if (ret < 0) {
dev_err(&ts->client->dev, "Failed read doze buf");
return -EINVAL;
}
if(doze_buf[2] != 0){
current_self_result = GTP_ERROR_SELF_TEST_ANALOG;
dev_err(&ts->client->dev, "sc error code %d\n",doze_buf[2]);
}
else{
current_self_result = GTP_SELF_TEST_SUCCESS;
}
ts->pdata->short_current_test = false;
return 0;
}
/*******************************************************
* Function:
* open current test result get //获取开路测试自检结果
* Input:
* ts: goodix tp private data
* Output:
* .
*********************************************************/
static int gtp_oc_handler(struct goodix_ts_data *ts)
{
u8 doze_buf[3] = {GTP_REG_OC_TEST_RESULT >> 8, GTP_REG_OC_TEST_RESULT & 0xFF};
int ret;
dev_info(&ts->client->dev, "enter gtp_oc_handler\n");
ret = gtp_i2c_read(ts->client, doze_buf, 3);
if (ret < 0) {
dev_err(&ts->client->dev, "Failed read doze buf");
current_self_result_oc = GTP_ERROR_TIMEOUT;
return -EINVAL;
}
if(doze_buf[2] != 0x00){
dev_err(&ts->client->dev, "TP open current\n");
current_self_result_oc = GTP_ERROR_OPEN_CURRENT;
doze_buf[0] = GTP_REG_OC_TEST_RESULT >> 8;
doze_buf[1] = GTP_REG_OC_TEST_RESULT & 0xff;
doze_buf[2] = 0;
gtp_i2c_write(ts->client, doze_buf, 3);
}
else{
current_self_result_oc = GTP_SELF_TEST_SUCCESS;
}
ts->pdata->open_current_test = false;
return 0;
}
#endif
/*******************************************************
* Function:
* Goodix touchscreen sensor report function
* Input:
* ts: goodix tp private data
* Output:
* None.
*********************************************************/
static void gtp_work_func(struct goodix_ts_data *ts)
{
u8 point_state = 0;
int key_value = 0;
s32 i = 0;
s32 ret = -1;
static int pre_key;
struct goodix_point_t points[GTP_MAX_TOUCH_ID];
#ifdef SELF_TEST_ENABLE
/* Short current test result event */
if(ts->pdata->short_current_test ){
gtp_sc_handler(ts);
}
if(ts->pdata->open_current_test ){
gtp_oc_handler(ts);
gtp_reset_guitar(ts->client, 20);
return;
}
#endif
......
}
/*******************************************************
* Function:
* Enter doze mode for sliding wakeup.
* Input:
* ts: goodix tp private data
* Output:
* 1: succeed, otherwise failed
*******************************************************/
static int gtp_enter_doze(struct goodix_ts_data *ts)
{
int ret = -1;
int retry = 0;
u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
(u8)GTP_REG_COMMAND, 8 };
/* resend doze command
* if (test_and_set_bit(DOZE_MODE, &ts->flags)) {
* dev_info(&ts->client->dev, "Already in doze mode\n");
* return SUCCESS;
* }
*/
set_bit(DOZE_MODE, &ts->flags);
dev_dbg(&ts->client->dev, "Entering gesture mode.");
while (retry++ < 5) {
i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8);
i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK;
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret < 0) {
dev_dbg(&ts->client->dev,
"failed to set doze flag into 0x8046, %d\n",
retry);
continue;
}
i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8);
i2c_control_buf[1] = (u8)GTP_REG_COMMAND;
ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
if (ret > 0) {
dev_dbg(&ts->client->dev, "Gesture mode enabled\n");
return ret;
}
usleep_range(10000, 11000);
}
dev_err(&ts->client->dev, "Failed enter doze mode\n");
clear_bit(DOZE_MODE, &ts->flags);
return ret;
}
/* short current test start cmd */
static s8 gtp_sc_test_start(struct goodix_ts_data *ts)
{
s8 ret = -1;
s8 retry = 0;
u8 i2c_control_buf[12] = { (u8)(GTP_REG_COMMAND_SC_TEST >> 8),
(u8)GTP_REG_COMMAND_SC_TEST, 0 };
/* Read the state */
while (retry++ < 20){
ret = gtp_i2c_read(ts->client, i2c_control_buf, 3);
if (ret > 0) {
if(i2c_control_buf[2] == 0xaa){
dev_info(&ts->client->dev, "TP enter to selftest mode successful\n");
i2c_control_buf[2] = 0;
break;
}
else{
dev_info(&ts->client->dev, "TP is not in selftest mode, %02x\n", i2c_control_buf[2]);
}
}
else{
dev_err(&ts->client->dev, "iic read error\n");
}
usleep_range(30000, 31000);
}
#ifdef SELF_TEST_ENABLE
static int do_goodix_self_test(void)
{
s8 ret;
/* Send cmd to touch ic to enter self test mode */
ret = gtp_enter_doze(Self_ts);//执行切换自检固件
usleep_range(30000, 31000);
/* Send start short current test cmd to touch ic */
ret = gtp_sc_test_start(Self_ts);//进入自检流程
Self_ts->pdata->short_current_test= true;
Self_ts->pdata->open_current_test = true;
return 1;
}
static ssize_t set_self_test_status(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long test_status;
if (kstrtoul(buf, 10, &test_status)) {
dev_info(dev, "invalid input!!!\n");
return 1;
}
current_self_test_status = test_status;
dev_info(dev, "set touch IC self test mode to %d\n", current_self_test_status);
if (current_self_test_status == 0) {
current_self_result = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
//current_self_result_oc = GTP_SELF_TEST_SUCCESS;
do_goodix_self_test();
}
return count;
}
static ssize_t get_self_test_status(struct device *dev, struct device_attribute *attr,
char *buf)
{
int len;
len = snprintf(buf, PAGE_SIZE, "%d", current_self_test_status);
dev_info(dev, "get self test state is %d, %d\n", current_self_test_status, len);
return len;
}
static DEVICE_ATTR(self_test_mode, S_IRUGO | S_IWUSR, get_self_test_status, set_self_test_status);
static ssize_t set_self_test_result(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return count;
}
static ssize_t get_self_test_result(struct device *dev, struct device_attribute *attr,
char *buf)
{
int len;
int result;
result = current_self_result || current_self_result_oc;
len = snprintf(buf, PAGE_SIZE, "%d", result);
//Self_ts->pdata->open_current_test = true;
dev_info(dev, "Get self test state is %d\n", current_self_result);
return len;
}
static DEVICE_ATTR(self_test_result, S_IRUGO | S_IWUSR, get_self_test_result, set_self_test_result);
#endif
static struct attribute *gtp_attrs[] = {
&dev_attr_workmode.attr,
&dev_attr_productinfo.attr,
#ifdef CONFIG_TOUCHSCREEN_GA657X_UPDATE
&dev_attr_dofwupdate.attr,
#endif
#ifdef SELF_TEST_ENABLE
&dev_attr_self_test_result.attr,
&dev_attr_self_test_mode.attr,
#endif
&dev_attr_drv_irq.attr,
&dev_attr_reset.attr,
NULL
};
static const struct attribute_group gtp_attr_group = {
.attrs = gtp_attrs,
};