/** * @file goodix.c * @goodix touch ic driver file. * * @Copyright (c) 2022 Semidrive Semiconductor. * @All rights reserved. * **/ #include #include #include #include "event_groups.h" #include #include "goodix.h" #include #include #define GOODIX_CONTACT_SIZE 8 #define GOODIX_MAX_CONTACTS 10 #define GOODIX_VENDOR_ID 0x0416 #define GTP_READ_COOR_ADDR 0x814E #define GOODIX_REG_ID 0x8140 struct goodix_ts_data { int id; int version; int vendor; touch_dev_t *ts_dev; EventGroupHandle_t ts_event; } g_goodix; int goodix_i2c_read(struct goodix_ts_data *goodix, uint8_t *buf, int len) { int ret = 0; sdrv_i2cdrv_bus_stat_t bus_stat; sdrv_i2cdrv_trans_stat_t trans_stat; sdrv_i2c_t *ctrl = goodix->ts_dev->i2c_ctrl; int addr = goodix->ts_dev->i2c_addr; /* get bus stat, if busy can not use */ bus_stat = sdrv_i2c_get_bus_stat(ctrl); if (bus_stat == SDRV_I2CDRV_BUS_BUSY) { ssdk_printf(SSDK_CRIT, "i2c ctrl %u busy\r\n", ctrl->cfg->id); return -1; } /* set bus stat to busy indicate bus be occupied now */ ret = sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_BUSY); if (ret < 0) { ssdk_printf(SSDK_CRIT, "i2c ctrl %u set bus stat fail\r\n", ctrl->cfg->id); return -2; } sdrv_i2c_write(ctrl, addr, buf, 2, 1000, false); trans_stat = sdrv_i2c_get_trans_stat(ctrl); if (trans_stat != SDRV_I2CDRV_TRANS_OK) { ssdk_printf(SSDK_CRIT, "%s write fail\r\n", __func__); ret = -3; goto end; } sdrv_i2c_read(ctrl, addr, buf + 2, len - 2, 1000, true); trans_stat = sdrv_i2c_get_trans_stat(ctrl); if (trans_stat != SDRV_I2CDRV_TRANS_OK) { ssdk_printf(SSDK_CRIT, "%s, read fail\r\n", __func__); ret = -4; goto end; } end: sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_IDLE); return ret; } int goodix_i2c_write(struct goodix_ts_data *goodix, uint8_t *buf, int len) { int ret = 0; sdrv_i2cdrv_bus_stat_t bus_stat; sdrv_i2cdrv_trans_stat_t trans_stat; sdrv_i2c_t *ctrl = goodix->ts_dev->i2c_ctrl; int addr = goodix->ts_dev->i2c_addr; /* get bus stat, if busy can not use */ bus_stat = sdrv_i2c_get_bus_stat(ctrl); if (bus_stat == SDRV_I2CDRV_BUS_BUSY) { ssdk_printf(SSDK_CRIT, "i2c ctrl %u busy\r\n", ctrl->cfg->id); return -1; } /* set bus stat to busy indicate bus be occupied now */ ret = sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_BUSY); if (ret < 0) { ssdk_printf(SSDK_CRIT, "i2c ctrl %u set bus stat fail\r\n", ctrl->cfg->id); return -2; } sdrv_i2c_write(ctrl, addr, buf, len, 1000, true); trans_stat = sdrv_i2c_get_trans_stat(ctrl); if (trans_stat != SDRV_I2CDRV_TRANS_OK) { ssdk_printf(SSDK_CRIT, "%s write fail\r\n", __func__); ret = -3; goto end; } end: sdrv_i2c_set_bus_stat(ctrl, SDRV_I2CDRV_BUS_IDLE); return ret; } static int goodix_read_version(struct goodix_ts_data *goodix) { uint8_t data[8] = {GOODIX_REG_ID >> 8, GOODIX_REG_ID & 0xFF}; char id_str[5]; int id, version; goodix_i2c_read(goodix, data, 8); //ssdk_printf(SSDK_ERR, "%s: %#x, %#x, %#x, %#x, %#x, %#x\r\n", __func__, // data[2], data[3], data[4], data[5], data[6], data[7]); memcpy(id_str, data + 2, 4); id = atoi(id_str); version = data[6] + (data[7] << 8); if (!id) return -1; else { goodix->id = id; goodix->version = version; goodix->vendor = GOODIX_VENDOR_ID; } ssdk_printf(SSDK_ERR, "%s: id:%d, version:%#x\r\n", __func__, id, version); return 0; } static int goodix_reset_device(struct goodix_ts_data *goodix) { sdrv_gpio_set_pin_output_level(goodix->ts_dev->rst, false); sdrv_gpio_set_pin_output_level(goodix->ts_dev->irq, false); //sdrv_gpio_set_pin_output_level(goodix->ts_dev->irq, // (goodix->ts_dev->i2c_addr == 0x14)); ts_mdelay(10); sdrv_gpio_set_pin_output_level(goodix->ts_dev->rst, true); //ts_mdelay(20); //sdrv_gpio_set_pin_output_level(goodix->ts_dev->irq, false); ts_mdelay(50); return 0; } static int goodix_ts_read_input_report(struct goodix_ts_data *goodix, uint8_t *data) { int count = 0; int touch_num = 0; uint8_t end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0}; /* store first finger point */ uint8_t point_data[11] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF}; /* store second~tenth finger point, if do have */ uint8_t point_data1[74] = {GTP_READ_COOR_ADDR >> 8, (GTP_READ_COOR_ADDR + 1 + GOODIX_CONTACT_SIZE) & 0xFF}; if (!goodix) return -1; while (count < 10) { goodix_i2c_read(goodix, point_data, 11); if (point_data[2] & (0x1 << 7)) { touch_num = point_data[2] & 0xf; memcpy(data, point_data + 2, 9); if (touch_num > 1) { goodix_i2c_read(goodix, point_data1, 2 + GOODIX_CONTACT_SIZE * (touch_num - 1)); memcpy(data + 9, point_data1 + 2, GOODIX_CONTACT_SIZE * (touch_num - 1)); } goodix_i2c_write(goodix, end_cmd, 3); return touch_num; } count++; ts_mdelay(2); } goodix_i2c_write(goodix, end_cmd, 3); return 0; } static void goodix_ts_thread(void *arg) { struct goodix_ts_data *goodix = arg; uint8_t pdata[81] = {0,}; int touch_num; touch_data_t *sdrv_datap = sdrv_touch_data_pointer(); while (1) { xEventGroupWaitBits(goodix->ts_event, 1, pdTRUE, pdFAIL, portMAX_DELAY); touch_num = goodix_ts_read_input_report(goodix, pdata); ssdk_printf(SSDK_ERR, "%s: 0x%x, (0x%x, 0x%x, 0x%x, 0x%x)\r\n", __func__, pdata[0], pdata[3], pdata[2], pdata[5], pdata[4]); if ((touch_num < 0) || (pdata[0] == 0)) { sdrv_gpio_pin_interrupt_enable(goodix->ts_dev->irq); continue; } sdrv_datap->touch_num = touch_num; for (int j = 0; j < touch_num; j++) { sdrv_datap->touch_point[j].id = *((uint8_t *)(pdata + 1 + GOODIX_CONTACT_SIZE * j)); sdrv_datap->touch_point[j].x = *((uint16_t *)(pdata + 2 + GOODIX_CONTACT_SIZE * j)); sdrv_datap->touch_point[j].y = *((uint16_t *)(pdata + 4 + GOODIX_CONTACT_SIZE * j)); } sdrv_gpio_pin_interrupt_enable(goodix->ts_dev->irq); } } static void goodix_irq_handler(uint32_t irq, uint32_t pin, void *arg) { BaseType_t yield = pdFALSE; struct goodix_ts_data *goodix = (struct goodix_ts_data *)arg; sdrv_gpio_pin_interrupt_disable(goodix->ts_dev->irq); if (xEventGroupSetBitsFromISR(goodix->ts_event, 1, &yield) != pdFAIL) portYIELD_FROM_ISR (yield); } static int goodix_config_device(struct goodix_ts_data *goodix) { goodix->ts_event = xEventGroupCreate(); xTaskCreate(goodix_ts_thread, "goodix", configTASK_IDLE_STACK_SIZE, goodix, (tskIDLE_PRIORITY + 2), NULL); sdrv_gpio_set_pin_interrupt(goodix->ts_dev->irq, GPIO_INTR_FALLING_EDGE); sdrv_gpio_register_interrupt_handler(goodix->ts_dev->irq, goodix_irq_handler, goodix); sdrv_gpio_pin_interrupt_enable(goodix->ts_dev->irq); return 0; } int goodix_touch_init(touch_dev_t *touch_dev) { int ret = 0; int retry = 0; g_goodix.ts_dev = touch_dev; do { goodix_reset_device(&g_goodix); if (!goodix_read_version(&g_goodix)) break; } while (++retry < 3); if (retry >= 3) { ssdk_printf(SSDK_ERR, "%s: read version fail\r\n", __func__); return -1; } ret = goodix_config_device(&g_goodix); if (ret) { ssdk_printf(SSDK_ERR, "%s: config device fail\r\n", __func__); return -1; } ssdk_printf(SSDK_ERR, "%s, ===done ok===\r\n", __func__); return 0; }