diff options
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | goodix_brl_fwupdate.c | 138 | ||||
-rw-r--r-- | goodix_brl_hw.c | 53 | ||||
-rw-r--r-- | goodix_brl_i2c.c | 11 | ||||
-rw-r--r-- | goodix_brl_spi.c | 15 | ||||
-rw-r--r-- | goodix_cfg_bin.c | 11 | ||||
-rw-r--r-- | goodix_ts_core.c | 201 | ||||
-rw-r--r-- | goodix_ts_core.h | 73 | ||||
-rw-r--r-- | goodix_ts_gesture.c | 308 | ||||
-rw-r--r-- | goodix_ts_inspect.c | 1333 | ||||
-rw-r--r-- | goodix_ts_proc.c | 376 | ||||
-rw-r--r-- | goodix_ts_tools.c | 1 | ||||
-rw-r--r-- | goodix_ts_utils.c | 69 |
14 files changed, 1597 insertions, 1003 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0183c58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.vscode +*.a +*.ko +*.o +*.cmd +*.builtin +*.order +*.mod.* @@ -9,4 +9,5 @@ goodix_core-y := \ goodix_brl_fwupdate.o \ goodix_ts_gesture.o \ goodix_ts_inspect.o \ - goodix_ts_tools.o + goodix_ts_tools.o \ + goodix_ts_proc.o diff --git a/goodix_brl_fwupdate.c b/goodix_brl_fwupdate.c index 6bce047..b01d572 100644 --- a/goodix_brl_fwupdate.c +++ b/goodix_brl_fwupdate.c @@ -192,6 +192,7 @@ struct firmware_summary { struct firmware_data { struct firmware_summary fw_summary; const struct firmware *firmware; + struct firmware *fw_sysfs; }; struct config_data { @@ -325,7 +326,11 @@ static int goodix_parse_firmware(struct firmware_data *fw_data) fw_summary = &fw_data->fw_summary; /* copy firmware head info */ - firmware = fw_data->firmware; + if (goodix_fw_update_ctrl.mode & UPDATE_MODE_SRC_SYSFS) + firmware = fw_data->fw_sysfs; + else + firmware = fw_data->firmware; + if (firmware->size < subsys_info_offset) { ts_err("Invalid firmware size:%zu", firmware->size); r = -EINVAL; @@ -337,7 +342,8 @@ static int goodix_parse_firmware(struct firmware_data *fw_data) fw_summary->size = le32_to_cpu(fw_summary->size); if (firmware->size != fw_summary->size + FW_FILE_CHECKSUM_OFFSET) { ts_err("Bad firmware, size not match, %zu != %d", - firmware->size, fw_summary->size + 6); + firmware->size, + fw_summary->size + FW_FILE_CHECKSUM_OFFSET); r = -EINVAL; goto err_size; } @@ -627,7 +633,8 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) ts_info("Success hold CPU"); /* enable misctl clock */ - if (fwu_ctrl->core_data->bus->ic_type == IC_TYPE_BERLIN_D) + if (fwu_ctrl->core_data->bus->ic_type == IC_TYPE_BERLIN_D || + fwu_ctrl->core_data->bus->ic_type == IC_TYPE_NOTTINGHAM) goodix_reg_write(misctl_reg, (u8 *)&enable_misctl_val, 4); else goodix_reg_write(misctl_reg, (u8 *)&enable_misctl_val, 1); @@ -703,7 +710,7 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd) } ts_info("flash cmd ack check pass"); - msleep(80); + msleep(50); retry = 20; for (i = 0; i < retry; i++) { ret = goodix_reg_read( @@ -716,7 +723,7 @@ static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd) ts_info("flash cmd status not ready, retry %d, ack 0x%x, status 0x%x, ret %d", i, tmp_cmd.ack, tmp_cmd.status, ret); - msleep(20); + usleep_range(10000, 11000); } ts_err("flash cmd status error %d, ack 0x%x, status 0x%x, ret %d", i, @@ -773,7 +780,7 @@ static int goodix_flash_package( ret = goodix_send_flash_cmd(&flash_cmd); if (!ret) { - ts_info("success write package to 0x%x, len %d", + ts_info("success write package to 0x%05X, len %d", flash_addr, pkg_len - 4); return 0; } @@ -817,7 +824,7 @@ static int goodix_flash_subsystem(struct fw_subsys_info *subsys) while (total_size > 0) { data_size = total_size > ISP_MAX_BUFFERSIZE ? ISP_MAX_BUFFERSIZE : total_size; - ts_info("Flash firmware to %08x,size:%u bytes", + ts_info("Flash firmware to 0x%05X,size:%u bytes", subsys_base_addr + offset, data_size); memcpy(fw_packet, &subsys->data[offset], data_size); @@ -828,7 +835,7 @@ static int goodix_flash_subsystem(struct fw_subsys_info *subsys) r = goodix_flash_package(subsys->type, fw_packet, subsys_base_addr + offset, data_size + 4); if (r) { - ts_err("failed flash to %08x,size:%u bytes", + ts_err("failed flash to 0x%05X,size:%u bytes", subsys_base_addr + offset, data_size); break; } @@ -866,7 +873,7 @@ static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl) /* flash config data first if we have */ if (fw_ctrl->ic_config && fw_ctrl->ic_config->len) { subsys_cfg.data = fw_ctrl->ic_config->data; - subsys_cfg.size = fw_ctrl->ic_config->len; + subsys_cfg.size = GOODIX_CFG_MAX_SIZE; subsys_cfg.flash_addr = config_data_reg; subsys_cfg.type = CONFIG_DATA_TYPE; r = goodix_flash_subsystem(&subsys_cfg); @@ -938,10 +945,10 @@ int goodix_fw_update_proc(struct fw_update_ctrl *fwu_ctrl) if (!(fwu_ctrl->mode & UPDATE_MODE_FORCE)) { ret = goodix_fw_version_compare(fwu_ctrl); if (!ret) { - ts_info("firmware upgraded"); + ts_info("no need to upgrade"); return 0; - } else - ts_info("need to upgrade"); + } + ts_info("need to upgrade"); } start_update: @@ -1029,73 +1036,29 @@ static ssize_t goodix_sysfs_update_en_store(struct device *dev, return -EINVAL; } -static ssize_t goodix_sysfs_fwsize_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; - int r = -EINVAL; - - if (fw_ctrl && fw_ctrl->fw_data.firmware) - r = snprintf(buf, PAGE_SIZE, "%zu\n", - fw_ctrl->fw_data.firmware->size); - return r; -} - -static ssize_t goodix_sysfs_fwsize_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; - struct firmware *fw; - u8 **data; - size_t size = 0; - - if (!fw_ctrl) - return -EINVAL; - - if (sscanf(buf, "%zu", &size) < 0 || !size) { - ts_err("Failed to get fwsize"); - return -EFAULT; - } - - /* use vmalloc to alloc huge memory */ - fw = vmalloc(sizeof(*fw) + size); - if (!fw) - return -ENOMEM; - mutex_lock(&fw_ctrl->mutex); - memset(fw, 0x00, sizeof(*fw) + size); - data = (u8 **)&fw->data; - *data = (u8 *)fw + sizeof(struct firmware); - fw->size = size; - fw_ctrl->fw_data.firmware = fw; - fw_ctrl->mode = UPDATE_MODE_SRC_SYSFS; - mutex_unlock(&fw_ctrl->mutex); - return count; -} - static ssize_t goodix_sysfs_fwimage_store(struct file *file, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t count) { - struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; - struct firmware_data *fw_data; - - fw_data = &fw_ctrl->fw_data; - - if (!fw_data->firmware) { - ts_err("Need set fw image size first"); - return -ENOMEM; - } + struct firmware **fw = &goodix_fw_update_ctrl.fw_data.fw_sysfs; - if (fw_data->firmware->size == 0) { - ts_err("Invalid firmware size"); - return -EINVAL; + if (*fw == NULL) { + *fw = kzalloc(sizeof(**fw), GFP_KERNEL); + if (*fw == NULL) + return -ENOMEM; + (*fw)->data = vmalloc(GOODIX_FW_MAX_SIEZE); + if ((*fw)->data == NULL) { + kfree(*fw); + *fw = NULL; + return -ENOMEM; + } } - if (pos + count > fw_data->firmware->size) + if (pos + count > GOODIX_FW_MAX_SIEZE) return -EFAULT; - mutex_lock(&fw_ctrl->mutex); - memcpy((u8 *)&fw_data->firmware->data[pos], buf, count); - mutex_unlock(&fw_ctrl->mutex); + memcpy((u8 *)&(*fw)->data[pos], buf, count); + (*fw)->size = pos + count; + return count; } @@ -1136,12 +1099,10 @@ static ssize_t goodix_sysfs_result_show( } static DEVICE_ATTR(update_en, 0220, NULL, goodix_sysfs_update_en_store); -static DEVICE_ATTR( - fwsize, 0664, goodix_sysfs_fwsize_show, goodix_sysfs_fwsize_store); static DEVICE_ATTR(result, 0664, goodix_sysfs_result_show, NULL); static struct attribute *goodix_fwu_attrs[] = { &dev_attr_update_en.attr, - &dev_attr_fwsize.attr, &dev_attr_result.attr }; + &dev_attr_result.attr }; static int goodix_fw_sysfs_init( struct goodix_ts_core *core_data, struct fw_update_ctrl *fw_ctrl) @@ -1168,7 +1129,7 @@ static int goodix_fw_sysfs_init( } fw_ctrl->attr_fwimage.attr.name = "fwimage"; - fw_ctrl->attr_fwimage.attr.mode = 0666; + fw_ctrl->attr_fwimage.attr.mode = 0664; fw_ctrl->attr_fwimage.size = 0; fw_ctrl->attr_fwimage.write = goodix_sysfs_fwimage_store; ret = sysfs_create_bin_file(fw_ctrl->kobj, &fw_ctrl->attr_fwimage); @@ -1244,7 +1205,6 @@ static inline void goodix_release_firmware(struct firmware_data *fw_data) static int goodix_fw_update_thread(void *data) { struct fw_update_ctrl *fwu_ctrl = data; - struct firmware *temp_firmware = NULL; ktime_t start, end; int r = -EINVAL; @@ -1253,37 +1213,45 @@ static int goodix_fw_update_thread(void *data) fwu_ctrl->status = UPSTA_NOTWORK; mutex_lock(&fwu_ctrl->mutex); + ts_debug("notify update start"); + goodix_ts_blocking_notify(NOTIFY_FWUPDATE_START, NULL); + if (fwu_ctrl->mode & UPDATE_MODE_SRC_REQUEST) { ts_info("Firmware request update starts"); r = goodix_request_firmware( &fwu_ctrl->fw_data, fwu_ctrl->fw_name); if (r < 0) goto out; - } else if (fwu_ctrl->mode & UPDATE_MODE_SRC_SYSFS) { - if (!fwu_ctrl->fw_data.firmware) { + if (!fwu_ctrl->fw_data.fw_sysfs) { ts_err("Invalid firmware from sysfs"); r = -EINVAL; goto out; } + if (fwu_ctrl->fw_data.fw_sysfs->size < 4096) { + ts_err("Invalid firmware size[%ld] from sysfs", + fwu_ctrl->fw_data.fw_sysfs->size); + vfree(fwu_ctrl->fw_data.fw_sysfs->data); + kfree(fwu_ctrl->fw_data.fw_sysfs); + fwu_ctrl->fw_data.fw_sysfs = NULL; + r = -EINVAL; + goto out; + } } else { ts_err("unknown update mode 0x%x", fwu_ctrl->mode); r = -EINVAL; goto out; } - ts_debug("notify update start"); - goodix_ts_blocking_notify(NOTIFY_FWUPDATE_START, NULL); - /* ready to update */ ts_debug("start update proc"); r = goodix_fw_update_proc(fwu_ctrl); /* clean */ - if (fwu_ctrl->mode & UPDATE_MODE_SRC_HEAD) { - kfree(fwu_ctrl->fw_data.firmware); - fwu_ctrl->fw_data.firmware = NULL; - temp_firmware = NULL; + if (fwu_ctrl->mode & UPDATE_MODE_SRC_SYSFS) { + vfree(fwu_ctrl->fw_data.fw_sysfs->data); + kfree(fwu_ctrl->fw_data.fw_sysfs); + fwu_ctrl->fw_data.fw_sysfs = NULL; } else if (fwu_ctrl->mode & UPDATE_MODE_SRC_REQUEST) { goodix_release_firmware(&fwu_ctrl->fw_data); } diff --git a/goodix_brl_hw.c b/goodix_brl_hw.c index 41bf117..19a2c1b 100644 --- a/goodix_brl_hw.c +++ b/goodix_brl_hw.c @@ -65,8 +65,7 @@ static int brl_select_spi_mode(struct goodix_ts_core *cd) if (!ret && r_value == w_value) return 0; } - ts_err("failed switch SPI mode after reset, ret:%d r_value:%02x", ret, - r_value); + ts_err("failed switch SPI mode, ret:%d r_value:%02x", ret, r_value); return -EINVAL; } @@ -93,8 +92,8 @@ static int brl_dev_confirm(struct goodix_ts_core *cd) } if (retry < 0) { - ret = -EINVAL; ts_err("device confirm failed, rx_buf:%*ph", 8, rx_buf); + return -EINVAL; } ts_info("device connected"); @@ -254,17 +253,12 @@ power_off: return ret; } -#define GOODIX_SLEEP_CMD 0x84 int brl_suspend(struct goodix_ts_core *cd) { - struct goodix_ts_cmd sleep_cmd; + u32 cmd_reg = cd->ic_info.misc.cmd_addr; + u8 sleep_cmd[] = { 0x00, 0x00, 0x04, 0x84, 0x88, 0x00 }; - sleep_cmd.cmd = GOODIX_SLEEP_CMD; - sleep_cmd.len = 4; - if (cd->hw_ops->send_cmd(cd, &sleep_cmd)) - ts_err("failed send sleep cmd"); - - return 0; + return cd->hw_ops->write(cd, cmd_reg, sleep_cmd, sizeof(sleep_cmd)); } int brl_resume(struct goodix_ts_core *cd) @@ -272,12 +266,16 @@ int brl_resume(struct goodix_ts_core *cd) return cd->hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS); } -#define GOODIX_GESTURE_CMD 0x12 +#define GOODIX_GESTURE_CMD_BA 0x12 +#define GOODIX_GESTURE_CMD 0xA6 int brl_gesture(struct goodix_ts_core *cd, int gesture_type) { struct goodix_ts_cmd cmd; - cmd.cmd = GOODIX_GESTURE_CMD; + if (cd->bus->ic_type == IC_TYPE_BERLIN_A) + cmd.cmd = GOODIX_GESTURE_CMD_BA; + else + cmd.cmd = GOODIX_GESTURE_CMD; cmd.len = 5; cmd.data[0] = gesture_type; if (cd->hw_ops->send_cmd(cd, &cmd)) @@ -373,7 +371,7 @@ static int brl_send_cmd(struct goodix_ts_core *cd, struct goodix_ts_cmd *cmd) ts_debug("cmd ack data %*ph", (int)sizeof(cmd_ack), cmd_ack.buf); if (cmd_ack.ack == CMD_ACK_OK) { - usleep_range(2000, 2100); + msleep(40); // wait for cmd response return 0; } if (cmd_ack.ack == CMD_ACK_BUSY || @@ -960,6 +958,7 @@ static int brl_esd_check(struct goodix_ts_core *cd) #define GOODIX_TOUCH_EVENT 0x80 #define GOODIX_REQUEST_EVENT 0x40 #define GOODIX_GESTURE_EVENT 0x20 +#define GOODIX_FP_EVENT 0x08 #define POINT_TYPE_STYLUS_HOVER 0x01 #define POINT_TYPE_STYLUS 0x03 @@ -1064,6 +1063,9 @@ static int goodix_touch_handler(struct goodix_ts_core *cd, } } + /* read done */ + hw_ops->after_event_handler(cd); + if (touch_num > 0) { point_type = buffer[IRQ_EVENT_HEAD_LEN] & 0x0F; if (point_type == POINT_TYPE_STYLUS || @@ -1090,6 +1092,8 @@ static int goodix_touch_handler(struct goodix_ts_core *cd, } } + ts_event->fp_flag = pre_buf[0] & GOODIX_FP_EVENT; + if (touch_num > 0 && (point_type == POINT_TYPE_STYLUS || point_type == POINT_TYPE_STYLUS_HOVER)) { /* stylus info */ @@ -1140,10 +1144,14 @@ static int brl_event_handler( return ret; } + if (pre_buf[0] == 0x00) { + ts_debug("invalid touch head"); + return -EINVAL; + } + if (checksum_cmp(pre_buf, IRQ_EVENT_HEAD_LEN, CHECKSUM_MODE_U8_LE)) { - ts_debug("touch head checksum err"); - ts_debug("touch_head %*ph", IRQ_EVENT_HEAD_LEN, pre_buf); - ts_event->retry = 1; + ts_debug("touch head checksum err[%*ph]", IRQ_EVENT_HEAD_LEN, + pre_buf); return -EINVAL; } @@ -1161,10 +1169,16 @@ static int brl_event_handler( else ts_debug("unsupported request code 0x%x", pre_buf[2]); } + if (event_status & GOODIX_GESTURE_EVENT) { ts_event->event_type = EVENT_GESTURE; ts_event->gesture_type = pre_buf[4]; + memcpy(ts_event->gesture_data, &pre_buf[8], + GOODIX_GESTURE_DATA_LEN); } + /* read done */ + hw_ops->after_event_handler(cd); + return 0; } @@ -1174,6 +1188,8 @@ static int brl_after_event_handler(struct goodix_ts_core *cd) struct goodix_ic_info_misc *misc = &cd->ic_info.misc; u8 sync_clean = 0; + if (cd->tools_ctrl_sync) + return 0; return hw_ops->write(cd, misc->touch_data_addr, &sync_clean, 1); } @@ -1318,7 +1334,8 @@ static int brl_get_capacitance_data( return -EIO; } - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) return brld_get_cap_data(cd, info); /* disable irq & close esd */ diff --git a/goodix_brl_i2c.c b/goodix_brl_i2c.c index be7d638..1173add 100644 --- a/goodix_brl_i2c.c +++ b/goodix_brl_i2c.c @@ -173,7 +173,7 @@ static int goodix_i2c_probe( return -EIO; /* get ic type */ - ret = goodix_get_ic_type(client->dev.of_node); + ret = goodix_get_ic_type(client->dev.of_node, &goodix_i2c_bus); if (ret < 0) return ret; @@ -225,13 +225,16 @@ static int goodix_i2c_remove(struct i2c_client *client) #ifdef CONFIG_OF static const struct of_device_id i2c_matches[] = { { - .compatible = "goodix,gt9897", + .compatible = "goodix,brl-a", }, { - .compatible = "goodix,gt9966", + .compatible = "goodix,brl-b", }, { - .compatible = "goodix,gt9916", + .compatible = "goodix,brl-d", + }, + { + .compatible = "goodix,nottingham", }, {}, }; diff --git a/goodix_brl_spi.c b/goodix_brl_spi.c index 8f53776..413cd9b 100644 --- a/goodix_brl_spi.c +++ b/goodix_brl_spi.c @@ -159,11 +159,8 @@ static int goodix_spi_write(struct device *dev, unsigned int addr, int ret = 0; tx_buf = kzalloc(SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL); - if (!tx_buf) { - ts_err("alloc tx_buf failed, size:%d", - SPI_WRITE_PREFIX_LEN + len); + if (!tx_buf) return -ENOMEM; - } spi_message_init(&spi_msg); memset(&xfers, 0, sizeof(xfers)); @@ -209,7 +206,7 @@ static int goodix_spi_probe(struct spi_device *spi) } /* get ic type */ - ret = goodix_get_ic_type(spi->dev.of_node); + ret = goodix_get_ic_type(spi->dev.of_node, &goodix_spi_bus); if (ret < 0) return ret; @@ -264,16 +261,16 @@ static int goodix_spi_remove(struct spi_device *spi) #ifdef CONFIG_OF static const struct of_device_id spi_matches[] = { { - .compatible = "goodix,gt9897S", + .compatible = "goodix,brl-a", }, { - .compatible = "goodix,gt9897T", + .compatible = "goodix,brl-b", }, { - .compatible = "goodix,gt9966S", + .compatible = "goodix,brl-d", }, { - .compatible = "goodix,gt9916S", + .compatible = "goodix,nottingham", }, {}, }; diff --git a/goodix_cfg_bin.c b/goodix_cfg_bin.c index 922aee4..42b991a 100644 --- a/goodix_cfg_bin.c +++ b/goodix_cfg_bin.c @@ -167,9 +167,9 @@ static int goodix_parse_cfg_bin(struct goodix_cfg_bin *cfg_bin) /*check cfg_bin valid*/ checksum = 0; - for (i = TS_BIN_VERSION_START_INDEX; i < cfg_bin->bin_data_len; i++) { + for (i = TS_BIN_VERSION_START_INDEX; i < cfg_bin->bin_data_len; i++) checksum += cfg_bin->bin_data[i]; - } + if (checksum != cfg_bin->head.checksum) { ts_err("cfg_bin checksum check filed 0x%02x != 0x%02x", cfg_bin->head.checksum, checksum); @@ -180,10 +180,8 @@ static int goodix_parse_cfg_bin(struct goodix_cfg_bin *cfg_bin) cfg_bin->cfg_pkgs = kzalloc( sizeof(struct goodix_cfg_package) * cfg_bin->head.pkg_num, GFP_KERNEL); - if (!cfg_bin->cfg_pkgs) { - ts_err("cfg_pkgs, allocate memory ERROR"); + if (!cfg_bin->cfg_pkgs) return -ENOMEM; - } /*get cfg_pkg's info*/ for (i = 0; i < cfg_bin->head.pkg_num; i++) { @@ -296,8 +294,7 @@ static int goodix_get_reg_and_cfg( err_out: /* parse config enter error, release memory alloced */ for (i = 0; i < GOODIX_MAX_CONFIG_GROUP; i++) { - if (cd->ic_configs[i]) - kfree(cd->ic_configs[i]); + kfree(cd->ic_configs[i]); cd->ic_configs[i] = NULL; } return -EINVAL; diff --git a/goodix_ts_core.c b/goodix_ts_core.c index 54e18af..1b25d94 100644 --- a/goodix_ts_core.c +++ b/goodix_ts_core.c @@ -26,6 +26,8 @@ #endif #include "goodix_ts_core.h" +/* goodix fb test */ +// #include "../../../video/fbdev/core/fb_firefly.h" #define GOODIX_DEFAULT_CFG_NAME "goodix_cfg_group.cfg" #define GOOIDX_INPUT_PHYS "goodix_ts/input0" @@ -86,8 +88,6 @@ static int __do_register_ext_module(struct goodix_ext_module *module) list_add(&module->list, insert_point->prev); mutex_unlock(&goodix_modules.mutex); - ts_info("Module [%s] registered,priority:%u", module->name, - module->priority); return 0; } @@ -133,13 +133,13 @@ int goodix_register_ext_module(struct goodix_ext_module *module) if (!module) return -EINVAL; - ts_info("goodix_register_ext_module IN"); + ts_info("IN"); goodix_core_module_init(); INIT_WORK(&module->work, goodix_register_ext_module_work); schedule_work(&module->work); - ts_info("goodix_register_ext_module OUT"); + ts_info("OUT"); return 0; } @@ -151,7 +151,8 @@ int goodix_register_ext_module_no_wait(struct goodix_ext_module *module) { if (!module) return -EINVAL; - ts_info("goodix_register_ext_module_no_wait IN"); + + ts_info("IN"); goodix_core_module_init(); /* driver probe failed */ if (core_module_prob_sate != CORE_MODULE_PROB_SUCCESS) { @@ -268,7 +269,7 @@ struct kobject *goodix_get_default_kobj(void) } /* show driver information */ -static ssize_t goodix_ts_driver_info_show( +static ssize_t driver_info_show( struct device *dev, struct device_attribute *attr, char *buf) { return snprintf( @@ -276,18 +277,19 @@ static ssize_t goodix_ts_driver_info_show( } /* show chip infoamtion */ -static ssize_t goodix_ts_chip_info_show( +static ssize_t chip_info_show( struct device *dev, struct device_attribute *attr, char *buf) { - struct goodix_ts_core *core_data = dev_get_drvdata(dev); - struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; + struct goodix_ts_core *cd = dev_get_drvdata(dev); + struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; struct goodix_fw_version chip_ver; + struct goodix_ic_info ic_info; u8 temp_pid[8] = { 0 }; int ret; int cnt = -EINVAL; if (hw_ops->read_version) { - ret = hw_ops->read_version(core_data, &chip_ver); + ret = hw_ops->read_version(cd, &chip_ver); if (!ret) { memcpy(temp_pid, chip_ver.rom_pid, sizeof(chip_ver.rom_pid)); @@ -306,13 +308,13 @@ static ssize_t goodix_ts_chip_info_show( } if (hw_ops->get_ic_info) { - ret = hw_ops->get_ic_info(core_data, &core_data->ic_info); + ret = hw_ops->get_ic_info(cd, &ic_info); if (!ret) { cnt += snprintf(&buf[cnt], PAGE_SIZE, "config_id:%x\n", - core_data->ic_info.version.config_id); + ic_info.version.config_id); cnt += snprintf(&buf[cnt], PAGE_SIZE, "config_version:%x\n", - core_data->ic_info.version.config_version); + ic_info.version.config_version); } } @@ -334,7 +336,7 @@ static ssize_t goodix_ts_reset_store(struct device *dev, } /* read config */ -static ssize_t goodix_ts_read_cfg_show( +static ssize_t read_cfg_show( struct device *dev, struct device_attribute *attr, char *buf) { struct goodix_ts_core *core_data = dev_get_drvdata(dev); @@ -409,8 +411,7 @@ static int goodix_ts_convert_0x_data( continue; if (temp_index >= m_size) { - ts_err("exchange cfg data error, overflow," - "temp_index:%d,m_size:%d", + ts_err("exchange cfg data error, overflow, temp_index:%d,m_size:%d", temp_index, m_size); return -EINVAL; } @@ -434,13 +435,9 @@ static ssize_t goodix_ts_send_cfg_store(struct device *dev, struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; struct goodix_ic_config *config = NULL; const struct firmware *cfg_img = NULL; - int en; int ret; - if (sscanf(buf, "%d", &en) != 1) - return -EINVAL; - - if (en != 1) + if (buf[0] != '1') return -EINVAL; hw_ops->irq_enable(core_data, false); @@ -720,11 +717,11 @@ static ssize_t goodix_ts_debug_log_store(struct device *dev, return count; } -static DEVICE_ATTR(driver_info, 0444, goodix_ts_driver_info_show, NULL); -static DEVICE_ATTR(chip_info, 0444, goodix_ts_chip_info_show, NULL); +static DEVICE_ATTR(driver_info, 0440, driver_info_show, NULL); +static DEVICE_ATTR(chip_info, 0440, chip_info_show, NULL); static DEVICE_ATTR(reset, 0220, NULL, goodix_ts_reset_store); static DEVICE_ATTR(send_cfg, 0220, NULL, goodix_ts_send_cfg_store); -static DEVICE_ATTR(read_cfg, 0444, goodix_ts_read_cfg_show, NULL); +static DEVICE_ATTR(read_cfg, 0440, read_cfg_show, NULL); static DEVICE_ATTR(reg_rw, 0664, goodix_ts_reg_rw_show, goodix_ts_reg_rw_store); static DEVICE_ATTR( irq_info, 0664, goodix_ts_irq_info_show, goodix_ts_irq_info_store); @@ -779,16 +776,12 @@ static int rawdata_proc_show(struct seq_file *m, void *v) int i; int index; - if (!m || !v || !cd) { - ts_err("rawdata_proc_show, input null ptr"); + if (!m || !v || !cd) return -EIO; - } info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - ts_err("Failed to alloc rawdata info memory"); + if (!info) return -ENOMEM; - } ret = cd->hw_ops->get_capacitance_data(cd, info); if (ret < 0) { @@ -799,19 +792,19 @@ static int rawdata_proc_show(struct seq_file *m, void *v) rx = info->buff[0]; tx = info->buff[1]; seq_printf(m, "TX:%d RX:%d\n", tx, rx); - seq_printf(m, "mutual_rawdata:\n"); + seq_puts(m, "mutual_rawdata:\n"); index = 2; for (i = 0; i < tx * rx; i++) { seq_printf(m, "%5d,", info->buff[index + i]); if ((i + 1) % tx == 0) - seq_printf(m, "\n"); + seq_puts(m, "\n"); } - seq_printf(m, "mutual_diffdata:\n"); + seq_puts(m, "mutual_diffdata:\n"); index += tx * rx; for (i = 0; i < tx * rx; i++) { seq_printf(m, "%3d,", info->buff[index + i]); if ((i + 1) % tx == 0) - seq_printf(m, "\n"); + seq_puts(m, "\n"); } exit: @@ -825,23 +818,39 @@ static int rawdata_proc_open(struct inode *inode, struct file *file) file, rawdata_proc_show, PDE_DATA(inode), PAGE_SIZE * 10); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) static const struct proc_ops rawdata_proc_fops = { .proc_open = rawdata_proc_open, .proc_read = seq_read, .proc_lseek = seq_lseek, .proc_release = single_release, }; +#else +static const struct file_operations rawdata_proc_fops = { + .open = rawdata_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif static void goodix_ts_procfs_init(struct goodix_ts_core *core_data) { + struct proc_dir_entry *proc_entry; + if (!proc_mkdir("goodix_ts", NULL)) return; - proc_create_data("goodix_ts/tp_capacitance_data", 0666, NULL, - &rawdata_proc_fops, core_data); + proc_entry = proc_create_data("goodix_ts/tp_capacitance_data", 0664, + NULL, &rawdata_proc_fops, core_data); + if (!proc_entry) + ts_err("failed to create proc entry"); + + driver_test_proc_init(core_data); } static void goodix_ts_procfs_exit(struct goodix_ts_core *core_data) { + driver_test_proc_remove(); remove_proc_entry("goodix_ts/tp_capacitance_data", NULL); remove_proc_entry("goodix_ts", NULL); } @@ -881,7 +890,7 @@ int goodix_ts_blocking_notify(enum ts_notify_event evt, void *v) return ret; } -#ifdef CONFIG_OF +#if IS_ENABLED(CONFIG_OF) /** * goodix_parse_dt_resolution - parse resolution from dt * @node: devicetree node @@ -1041,15 +1050,18 @@ static int goodix_parse_dt( return r; } + /* get sleep mode flag */ + board_data->sleep_enable = + of_property_read_bool(node, "goodix,sleep-enable"); + /*get pen-enable switch and pen keys, must after "key map"*/ board_data->pen_enable = of_property_read_bool(node, "goodix,pen-enable"); - if (board_data->pen_enable) - ts_info("goodix pen enabled"); - ts_debug("[DT]x:%d, y:%d, w:%d, p:%d", board_data->panel_max_x, - board_data->panel_max_y, board_data->panel_max_w, - board_data->panel_max_p); + ts_info("[DT]x:%d, y:%d, w:%d, p:%d sleep_enable:%d pen_enable:%d", + board_data->panel_max_x, board_data->panel_max_y, + board_data->panel_max_w, board_data->panel_max_p, + board_data->sleep_enable, board_data->pen_enable); return 0; } #endif @@ -1067,6 +1079,10 @@ static void goodix_ts_report_pen( input_report_abs(dev, ABS_X, pen_data->coords.x); input_report_abs(dev, ABS_Y, pen_data->coords.y); input_report_abs(dev, ABS_PRESSURE, pen_data->coords.p); + if (pen_data->coords.p == 0) + input_report_abs(dev, ABS_DISTANCE, 1); + else + input_report_abs(dev, ABS_DISTANCE, 0); input_report_abs(dev, ABS_TILT_X, pen_data->coords.tilt_x); input_report_abs(dev, ABS_TILT_Y, pen_data->coords.tilt_y); ts_debug( @@ -1102,7 +1118,7 @@ static void goodix_ts_report_finger( for (i = 0; i < GOODIX_MAX_TOUCH; i++) { if (touch_data->coords[i].status == TS_TOUCH) { - ts_debug("report: id %d, x %d, y %d, w %d", i, + ts_debug("report: id[%d], x %d, y %d, w %d", i, touch_data->coords[i].x, touch_data->coords[i].y, touch_data->coords[i].w); @@ -1193,15 +1209,10 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) goodix_ts_report_pen( core_data->pen_dev, &ts_event->pen_data); } - if (ts_event->event_type == EVENT_REQUEST) { + if (ts_event->event_type == EVENT_REQUEST) goodix_ts_request_handle(core_data, ts_event); - } } - if (!core_data->tools_ctrl_sync && !ts_event->retry) - hw_ops->after_event_handler(core_data); - ts_event->retry = 0; - return IRQ_HANDLED; } @@ -1397,15 +1408,12 @@ static int goodix_ts_input_dev_config(struct goodix_ts_core *core_data) input_dev->id.vendor = 0xBEEF; input_dev->id.version = 10427; - __set_bit(EV_SYN, input_dev->evbit); - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(BTN_TOUCH, input_dev->keybit); - __set_bit(BTN_TOOL_FINGER, input_dev->keybit); - -#ifdef INPUT_PROP_DIRECT - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); -#endif + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_ABS, input_dev->evbit); + set_bit(BTN_TOUCH, input_dev->keybit); + set_bit(BTN_TOOL_FINGER, input_dev->keybit); + set_bit(INPUT_PROP_DIRECT, input_dev->propbit); /* set input parameters */ input_set_abs_params( @@ -1423,6 +1431,8 @@ static int goodix_ts_input_dev_config(struct goodix_ts_core *core_data) #endif input_set_capability(input_dev, EV_KEY, KEY_POWER); + input_set_capability(input_dev, EV_KEY, KEY_WAKEUP); + input_set_capability(input_dev, EV_KEY, KEY_GOTO); r = input_register_device(input_dev); if (r < 0) { @@ -1455,19 +1465,20 @@ static int goodix_ts_pen_dev_config(struct goodix_ts_core *core_data) pen_dev->id.version = 10427; pen_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - __set_bit(ABS_X, pen_dev->absbit); - __set_bit(ABS_Y, pen_dev->absbit); - __set_bit(ABS_TILT_X, pen_dev->absbit); - __set_bit(ABS_TILT_Y, pen_dev->absbit); - __set_bit(BTN_STYLUS, pen_dev->keybit); - __set_bit(BTN_STYLUS2, pen_dev->keybit); - __set_bit(BTN_TOUCH, pen_dev->keybit); - __set_bit(BTN_TOOL_PEN, pen_dev->keybit); - __set_bit(INPUT_PROP_DIRECT, pen_dev->propbit); + set_bit(ABS_X, pen_dev->absbit); + set_bit(ABS_Y, pen_dev->absbit); + set_bit(ABS_TILT_X, pen_dev->absbit); + set_bit(ABS_TILT_Y, pen_dev->absbit); + set_bit(BTN_STYLUS, pen_dev->keybit); + set_bit(BTN_STYLUS2, pen_dev->keybit); + set_bit(BTN_TOUCH, pen_dev->keybit); + set_bit(BTN_TOOL_PEN, pen_dev->keybit); + set_bit(INPUT_PROP_DIRECT, pen_dev->propbit); input_set_abs_params(pen_dev, ABS_X, 0, ts_bdata->panel_max_x, 0, 0); input_set_abs_params(pen_dev, ABS_Y, 0, ts_bdata->panel_max_y, 0, 0); input_set_abs_params( pen_dev, ABS_PRESSURE, 0, ts_bdata->panel_max_p, 0, 0); + input_set_abs_params(pen_dev, ABS_DISTANCE, 0, 255, 0, 0); input_set_abs_params(pen_dev, ABS_TILT_X, -GOODIX_PEN_MAX_TILT, GOODIX_PEN_MAX_TILT, 0, 0); input_set_abs_params(pen_dev, ABS_TILT_Y, -GOODIX_PEN_MAX_TILT, @@ -1553,9 +1564,9 @@ static void goodix_ts_esd_on(struct goodix_ts_core *cd) return; atomic_set(&ts_esd->esd_on, 1); - if (!schedule_delayed_work(&ts_esd->esd_work, 2 * HZ)) { + if (!schedule_delayed_work(&ts_esd->esd_work, 2 * HZ)) ts_info("esd work already in workqueue"); - } + ts_info("esd on"); } @@ -1652,7 +1663,7 @@ static void goodix_ts_release_connects(struct goodix_ts_core *core_data) /** * goodix_ts_suspend - Touchscreen suspend function - * Called by PM/FB/EARLYSUSPEN module to put the device to sleep + * Called by PM/FB/EARLYSUSPEN module to put the device to sleep */ static int goodix_ts_suspend(struct goodix_ts_core *core_data) { @@ -1697,8 +1708,10 @@ static int goodix_ts_suspend(struct goodix_ts_core *core_data) mutex_unlock(&goodix_modules.mutex); /* enter sleep mode or power off */ - if (hw_ops->suspend) + if (core_data->board_data.sleep_enable) hw_ops->suspend(core_data); + else + goodix_ts_power_off(core_data); /* inform exteranl modules */ mutex_lock(&goodix_modules.mutex); @@ -1743,6 +1756,7 @@ static int goodix_ts_resume(struct goodix_ts_core *core_data) ts_info("Resume start"); atomic_set(&core_data->suspended, 0); + hw_ops->irq_enable(core_data, false); mutex_lock(&goodix_modules.mutex); if (!list_empty(&goodix_modules.head)) { @@ -1765,8 +1779,10 @@ static int goodix_ts_resume(struct goodix_ts_core *core_data) mutex_unlock(&goodix_modules.mutex); /* reset device or power on*/ - if (hw_ops->resume) + if (core_data->board_data.sleep_enable) hw_ops->resume(core_data); + else + goodix_ts_power_on(core_data); mutex_lock(&goodix_modules.mutex); if (!list_empty(&goodix_modules.head)) { @@ -1797,7 +1813,7 @@ out: return 0; } -#ifdef CONFIG_FB +#if IS_ENABLED(CONFIG_FB) /** * goodix_ts_fb_notifier_callback - Framebuffer notifier callback * Called by kernel during framebuffer blanck/unblank phrase @@ -1810,10 +1826,9 @@ int goodix_ts_fb_notifier_callback( struct fb_event *fb_event = data; if (fb_event && fb_event->data && core_data) { - if (event == FB_EARLY_EVENT_BLANK) { - /* before fb blank */ - } else if (event == FB_EVENT_BLANK) { + if (event == FB_EVENT_BLANK) { int *blank = fb_event->data; + if (*blank == FB_BLANK_UNBLANK) goodix_ts_resume(core_data); else if (*blank == FB_BLANK_POWERDOWN) @@ -1825,8 +1840,8 @@ int goodix_ts_fb_notifier_callback( } #endif -#ifdef CONFIG_PM -#if !defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND) +#if IS_ENABLED(CONFIG_PM) +#if !IS_ENABLED(CONFIG_FB) && !IS_ENABLED(CONFIG_HAS_EARLYSUSPEND) /** * goodix_ts_pm_suspend - PM suspend function * Called by kernel during system suspend phrase @@ -1907,7 +1922,7 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) } ts_info("success register irq"); -#ifdef CONFIG_FB +#if IS_ENABLED(CONFIG_FB) cd->fb_notifier.notifier_call = goodix_ts_fb_notifier_callback; if (fb_register_client(&cd->fb_notifier)) ts_err("Failed to register fb notifier client:%d", ret); @@ -2042,8 +2057,7 @@ err_out: ts_err("stage2 init failed"); cd->init_stage = CORE_INIT_FAIL; for (i = 0; i < GOODIX_MAX_CONFIG_GROUP; i++) { - if (cd->ic_configs[i]) - kfree(cd->ic_configs[i]); + kfree(cd->ic_configs[i]); cd->ic_configs[i] = NULL; } return ret; @@ -2063,6 +2077,17 @@ static int goodix_start_later_init(struct goodix_ts_core *ts_core) return 0; } +/* goodix fb test */ +// static void test_suspend(void) +// { +// goodix_ts_suspend(goodix_modules.core_data); +// } + +// static void test_resume(void) +// { +// goodix_ts_resume(goodix_modules.core_data); +// } + /** * goodix_ts_probe - called by kernel when Goodix touch * platform driver is added. @@ -2073,7 +2098,7 @@ static int goodix_ts_probe(struct platform_device *pdev) struct goodix_bus_interface *bus_interface; int ret; - ts_info("goodix_ts_probe IN"); + ts_info("IN"); bus_interface = pdev->dev.platform_data; if (!bus_interface) { @@ -2085,7 +2110,6 @@ static int goodix_ts_probe(struct platform_device *pdev) core_data = devm_kzalloc( &pdev->dev, sizeof(struct goodix_ts_core), GFP_KERNEL); if (!core_data) { - ts_err("Failed to allocate memory for core data"); core_module_prob_sate = CORE_MODULE_PROB_FAILED; return -ENOMEM; } @@ -2141,6 +2165,9 @@ static int goodix_ts_probe(struct platform_device *pdev) /* debug node init */ goodix_tools_init(); + /* goodix fb test */ + // fb_firefly_register(test_suspend, test_resume); + core_data->init_stage = CORE_INIT_STAGE1; goodix_modules.core_data = core_data; core_module_prob_sate = CORE_MODULE_PROB_SUCCESS; @@ -2171,7 +2198,7 @@ static int goodix_ts_remove(struct platform_device *pdev) gesture_module_exit(); inspect_module_exit(); hw_ops->irq_enable(core_data, false); -#ifdef CONFIG_FB +#if IS_ENABLED(CONFIG_FB) fb_unregister_client(&core_data->fb_notifier); #endif core_module_prob_sate = CORE_MODULE_REMOVED; @@ -2190,9 +2217,9 @@ static int goodix_ts_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#if IS_ENABLED(CONFIG_PM) static const struct dev_pm_ops dev_pm_ops = { -#if !defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND) +#if !IS_ENABLED(CONFIG_FB) && !IS_ENABLED(CONFIG_HAS_EARLYSUSPEND) .suspend = goodix_ts_pm_suspend, .resume = goodix_ts_pm_resume, #endif @@ -2208,7 +2235,7 @@ static struct platform_driver goodix_ts_driver = { .driver = { .name = GOODIX_CORE_DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM +#if IS_ENABLED(CONFIG_PM) .pm = &dev_pm_ops, #endif }, diff --git a/goodix_ts_core.h b/goodix_ts_core.h index a37fb50..9269acd 100644 --- a/goodix_ts_core.h +++ b/goodix_ts_core.h @@ -1,3 +1,19 @@ +/* + * Goodix Gesture Module + * + * Copyright (C) 2019 - 2020 Goodix, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ #ifndef _GOODIX_TS_CORE_H_ #define _GOODIX_TS_CORE_H_ #include <asm/unaligned.h> @@ -15,25 +31,27 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#ifdef CONFIG_OF +#if IS_ENABLED(CONFIG_OF) #include <linux/of_gpio.h> #include <linux/regulator/consumer.h> #endif -#ifdef CONFIG_FB +#if IS_ENABLED(CONFIG_FB) #include <linux/fb.h> #include <linux/notifier.h> #endif #define GOODIX_CORE_DRIVER_NAME "goodix_ts" #define GOODIX_PEN_DRIVER_NAME "goodix_ts,pen" -#define GOODIX_DRIVER_VERSION "v2.0.0" +#define GOODIX_DRIVER_VERSION "v1.0.0" #define GOODIX_MAX_TOUCH 10 #define GOODIX_PEN_MAX_PRESSURE 4096 #define GOODIX_MAX_PEN_KEY 2 #define GOODIX_PEN_MAX_TILT 90 #define GOODIX_CFG_MAX_SIZE 4096 +#define GOODIX_FW_MAX_SIEZE (300 * 1024) #define GOODIX_MAX_STR_LABEL_LEN 32 #define GOODIX_MAX_FRAMEDATA_LEN 1700 +#define GOODIX_GESTURE_DATA_LEN 16 #define GOODIX_NORMAL_RESET_DELAY_MS 100 #define GOODIX_HOLD_CPU_RESET_DELAY_MS 5 @@ -45,6 +63,12 @@ #define TS_DEFAULT_FIRMWARE "goodix_firmware.bin" #define TS_DEFAULT_CFG_BIN "goodix_cfg_group.bin" +enum GOODIX_GESTURE_TYP { + GESTURE_SINGLE_TAP = (1 << 0), + GESTURE_DOUBLE_TAP = (1 << 1), + GESTURE_FOD_PRESS = (1 << 2) +}; + enum CORD_PROB_STA { CORE_MODULE_UNPROBED = 0, CORE_MODULE_PROB_SUCCESS = 1, @@ -62,6 +86,7 @@ enum GOODIX_ERR_CODE { GOODIX_EOTHER = (1 << 7) }; +/* MAIN-ID */ enum IC_TYPE_ID { IC_TYPE_NONE, IC_TYPE_NORMANDY, @@ -69,7 +94,17 @@ enum IC_TYPE_ID { IC_TYPE_YELLOWSTONE, IC_TYPE_BERLIN_A, IC_TYPE_BERLIN_B, - IC_TYPE_BERLIN_D + IC_TYPE_BERLIN_D, + IC_TYPE_NOTTINGHAM +}; + +/* SUB-ID + * sub type of berlinB serial IC. + * for convenience we put the MAIN-ID on the hith bits, + * hith 8 bits is MAIN-ID, low 8 bits is MIN-ID + */ +enum BERLIN_B_SUB_ID { + IC_TYPE_SUB_B2 = (IC_TYPE_BERLIN_B << 8) | 0x2, }; enum GOODIX_IC_CONFIG_TYPE { @@ -90,8 +125,8 @@ enum CHECKSUM_MODE { CHECKSUM_MODE_U16_LE, }; -#define MAX_SCAN_FREQ_NUM 5 -#define MAX_SCAN_RATE_NUM 5 +#define MAX_SCAN_FREQ_NUM 8 +#define MAX_SCAN_RATE_NUM 8 #define MAX_FREQ_NUM_STYLUS 8 #define MAX_STYLUS_SCAN_FREQ_NUM 6 #pragma pack(1) @@ -265,6 +300,7 @@ struct goodix_ts_board_data { unsigned int panel_max_p; /*pressure*/ bool pen_enable; + bool sleep_enable; char fw_name[GOODIX_MAX_STR_LABEL_LEN]; char cfg_bin_name[GOODIX_MAX_STR_LABEL_LEN]; }; @@ -366,10 +402,11 @@ struct goodix_pen_data { * @event_data: event data */ struct goodix_ts_event { - int retry; enum ts_event_type event_type; + u8 fp_flag; /* finger print DOWN flag */ u8 request_code; /* represent the request type */ u8 gesture_type; + u8 gesture_data[GOODIX_GESTURE_DATA_LEN]; struct goodix_touch_data touch_data; struct goodix_pen_data pen_data; }; @@ -383,6 +420,7 @@ enum goodix_ic_bus_type { struct goodix_bus_interface { int bus_type; int ic_type; + int sub_ic_type; struct device *dev; int (*read)(struct device *dev, unsigned int addr, unsigned char *data, unsigned int len); @@ -412,8 +450,7 @@ struct goodix_ts_hw_ops { int (*esd_check)(struct goodix_ts_core *cd); int (*event_handler)( struct goodix_ts_core *cd, struct goodix_ts_event *ts_event); - int (*after_event_handler)( - struct goodix_ts_core *cd); /* clean sync flag */ + int (*after_event_handler)(struct goodix_ts_core *cd); int (*get_capacitance_data)( struct goodix_ts_core *cd, struct ts_rawdata_info *info); }; @@ -461,6 +498,7 @@ struct goodix_ts_core { struct goodix_ic_config *ic_configs[GOODIX_MAX_CONFIG_GROUP]; struct regulator *avdd; struct regulator *iovdd; + unsigned char gesture_type; int power_on; int irq; @@ -474,7 +512,7 @@ struct goodix_ts_core { struct notifier_block ts_notifier; struct goodix_ts_esd ts_esd; -#ifdef CONFIG_FB +#if IS_ENABLED(CONFIG_FB) struct notifier_block fb_notifier; #endif }; @@ -548,8 +586,9 @@ struct goodix_ext_module { */ struct goodix_ext_attribute { struct attribute attr; - ssize_t (*show)(struct goodix_ext_module *, char *); - ssize_t (*store)(struct goodix_ext_module *, const char *, size_t); + ssize_t (*show)(struct goodix_ext_module *module, char *buf); + ssize_t (*store)( + struct goodix_ext_module *module, const char *buf, size_t len); }; /* external attrs helper macro */ @@ -562,7 +601,7 @@ struct goodix_ext_attribute { /* external attrs helper macro, used to define external attrs */ #define DEFINE_EXTMOD_ATTR(_name, _mode, _show, _store) \ static struct goodix_ext_attribute ext_attr_##_name = \ - __EXTMOD_ATTR(_name, _mode, _show, _store); + __EXTMOD_ATTR(_name, _mode, _show, _store) /* log macro */ extern bool debug_log_flag; @@ -626,13 +665,13 @@ int checksum_cmp(const u8 *data, int size, int mode); int is_risk_data(const u8 *data, int size); u32 goodix_get_file_config_id(u8 *ic_config); void goodix_rotate_abcd2cbad(int tx, int rx, s16 *data); -int goodix_gesture_enable(int enable); int goodix_fw_update_init(struct goodix_ts_core *core_data); void goodix_fw_update_uninit(void); int goodix_do_fw_update(struct goodix_ic_config *ic_config, int mode); -int goodix_get_ic_type(struct device_node *node); +int goodix_get_ic_type( + struct device_node *node, struct goodix_bus_interface *bus_inf); int gesture_module_init(void); void gesture_module_exit(void); int inspect_module_init(void); @@ -640,4 +679,8 @@ void inspect_module_exit(void); int goodix_tools_init(void); void goodix_tools_exit(void); +int driver_test_proc_init(struct goodix_ts_core *core_data); +void driver_test_proc_remove(void); +int goodix_do_inspect(struct goodix_ts_core *cd, struct ts_rawdata_info *info); + #endif diff --git a/goodix_ts_gesture.c b/goodix_ts_gesture.c index 43899b4..837b9a4 100644 --- a/goodix_ts_gesture.c +++ b/goodix_ts_gesture.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/input/mt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -27,9 +28,10 @@ #include <linux/string.h> #include <linux/version.h> -#define QUERYBIT(longlong, bit) (!!(longlong[bit / 8] & (1 << bit % 8))) - -#define GSX_GESTURE_TYPE_LEN 32 +#define GOODIX_GESTURE_DOUBLE_TAP 0xCC +#define GOODIX_GESTURE_SINGLE_TAP 0x4C +#define GOODIX_GESTURE_FOD_DOWN 0x46 +#define GOODIX_GESTURE_FOD_UP 0x55 /* * struct gesture_module - gesture module data @@ -41,156 +43,160 @@ */ struct gesture_module { atomic_t registered; - rwlock_t rwlock; - u8 gesture_type[GSX_GESTURE_TYPE_LEN]; - u8 gesture_data; + struct goodix_ts_core *ts_core; struct goodix_ext_module module; }; static struct gesture_module *gsx_gesture; /*allocated in gesture init module*/ static bool module_initialized; -int goodix_gesture_enable(int enable) +static ssize_t gsx_double_type_show(struct goodix_ext_module *module, char *buf) { - int ret = 0; + struct gesture_module *gsx = module->priv_data; + unsigned char type = gsx->ts_core->gesture_type; - if (!module_initialized) + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); return 0; + } + + return sprintf(buf, "%s\n", + (type & GESTURE_DOUBLE_TAP) ? "enable" : "disable"); +} + +static ssize_t gsx_double_type_store( + struct goodix_ext_module *module, const char *buf, size_t count) +{ + struct gesture_module *gsx = module->priv_data; - if (enable) { - if (atomic_read(&gsx_gesture->registered)) - ts_info("gesture module has been already registered"); - else - ret = goodix_register_ext_module_no_wait( - &gsx_gesture->module); - } else { - if (!atomic_read(&gsx_gesture->registered)) - ts_info("gesture module has been already unregistered"); - else - ret = goodix_unregister_ext_module( - &gsx_gesture->module); + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; } - return ret; + if (buf[0] == '1') { + ts_info("enable double tap"); + gsx->ts_core->gesture_type |= GESTURE_DOUBLE_TAP; + } else if (buf[0] == '0') { + ts_info("disable double tap"); + gsx->ts_core->gesture_type &= ~GESTURE_DOUBLE_TAP; + } else + ts_err("invalid cmd[%d]", buf[0]); + + return count; } -/** - * gsx_gesture_type_show - show valid gesture type - * - * @module: pointer to goodix_ext_module struct - * @buf: pointer to output buffer - * Returns >=0 - succeed,< 0 - failed - */ -static ssize_t gsx_gesture_type_show( - struct goodix_ext_module *module, char *buf) +static ssize_t gsx_single_type_show(struct goodix_ext_module *module, char *buf) { - int count = 0, i, ret = 0; - unsigned char *type; + struct gesture_module *gsx = module->priv_data; + unsigned char type = gsx->ts_core->gesture_type; - type = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!type) - return -ENOMEM; - read_lock(&gsx_gesture->rwlock); - for (i = 0; i < 256; i++) { - if (QUERYBIT(gsx_gesture->gesture_type, i)) { - count += scnprintf(type + count, PAGE_SIZE, "%02x,", i); - } + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; } - if (count > 0) - ret = scnprintf(buf, PAGE_SIZE, "%s\n", type); - read_unlock(&gsx_gesture->rwlock); - kfree(type); - return ret; + return sprintf(buf, "%s\n", + (type & GESTURE_SINGLE_TAP) ? "enable" : "disable"); } -/** - * gsx_gesture_type_store - set vailed gesture - * - * @module: pointer to goodix_ext_module struct - * @buf: pointer to valid gesture type - * @count: length of buf - * Returns >0 - valid gestures, < 0 - failed - */ -static ssize_t gsx_gesture_type_store( +static ssize_t gsx_single_type_store( struct goodix_ext_module *module, const char *buf, size_t count) { - int i; + struct gesture_module *gsx = module->priv_data; - if (count <= 0 || count > 256 || buf == NULL) { - ts_err("Parameter error"); - return -EINVAL; + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; } - write_lock(&gsx_gesture->rwlock); - memset(gsx_gesture->gesture_type, 0, GSX_GESTURE_TYPE_LEN); - for (i = 0; i < count; i++) - gsx_gesture->gesture_type[buf[i] / 8] |= (0x1 << buf[i] % 8); - write_unlock(&gsx_gesture->rwlock); + if (buf[0] == '1') { + ts_info("enable single tap"); + gsx->ts_core->gesture_type |= GESTURE_SINGLE_TAP; + } else if (buf[0] == '0') { + ts_info("disable single tap"); + gsx->ts_core->gesture_type &= ~GESTURE_SINGLE_TAP; + } else + ts_err("invalid cmd[%d]", buf[0]); return count; } -static ssize_t gsx_gesture_enable_show( - struct goodix_ext_module *module, char *buf) +static ssize_t gsx_fod_type_show(struct goodix_ext_module *module, char *buf) { - return scnprintf( - buf, PAGE_SIZE, "%d\n", atomic_read(&gsx_gesture->registered)); + struct gesture_module *gsx = module->priv_data; + unsigned char type = gsx->ts_core->gesture_type; + + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; + } + + return sprintf( + buf, "%s\n", (type & GESTURE_FOD_PRESS) ? "enable" : "disable"); } -static ssize_t gsx_gesture_enable_store( +static ssize_t gsx_fod_type_store( struct goodix_ext_module *module, const char *buf, size_t count) { - bool val; - int ret; + struct gesture_module *gsx = module->priv_data; - ret = strtobool(buf, &val); - if (ret < 0) - return ret; + if (!gsx) + return -EIO; - if (val) { - ret = goodix_gesture_enable(1); - return ret ? ret : count; - } else { - ret = goodix_gesture_enable(0); - return ret ? ret : count; + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; } -} - -static ssize_t gsx_gesture_data_show( - struct goodix_ext_module *module, char *buf) -{ - ssize_t count; - read_lock(&gsx_gesture->rwlock); - count = scnprintf(buf, PAGE_SIZE, "gesture type code:0x%x\n", - gsx_gesture->gesture_data); - read_unlock(&gsx_gesture->rwlock); + if (buf[0] == '1') { + ts_info("enable fod"); + gsx->ts_core->gesture_type |= GESTURE_FOD_PRESS; + } else if (buf[0] == '0') { + ts_info("disable fod"); + gsx->ts_core->gesture_type &= ~GESTURE_FOD_PRESS; + } else + ts_err("invalid cmd[%d]", buf[0]); return count; } const struct goodix_ext_attribute gesture_attrs[] = { __EXTMOD_ATTR( - type, 0666, gsx_gesture_type_show, gsx_gesture_type_store), - __EXTMOD_ATTR(enable, 0666, gsx_gesture_enable_show, - gsx_gesture_enable_store), - __EXTMOD_ATTR(data, 0444, gsx_gesture_data_show, NULL) + double_en, 0664, gsx_double_type_show, gsx_double_type_store), + __EXTMOD_ATTR( + single_en, 0664, gsx_single_type_show, gsx_single_type_store), + __EXTMOD_ATTR(fod_en, 0664, gsx_fod_type_show, gsx_fod_type_store), }; static int gsx_gesture_init( struct goodix_ts_core *cd, struct goodix_ext_module *module) { + struct gesture_module *gsx = module->priv_data; + if (!cd || !cd->hw_ops->gesture) { ts_err("gesture unsupported"); return -EINVAL; } - ts_info("gesture switch: ON"); - ts_debug("enable all gesture type"); - /* set all bit to 1 to enable all gesture wakeup */ - memset(gsx_gesture->gesture_type, 0xff, GSX_GESTURE_TYPE_LEN); - atomic_set(&gsx_gesture->registered, 1); + gsx->ts_core = cd; + gsx->ts_core->gesture_type = 0; + atomic_set(&gsx->registered, 1); return 0; } @@ -198,15 +204,14 @@ static int gsx_gesture_init( static int gsx_gesture_exit( struct goodix_ts_core *cd, struct goodix_ext_module *module) { + struct gesture_module *gsx = module->priv_data; + if (!cd || !cd->hw_ops->gesture) { ts_err("gesture unsupported"); return -EINVAL; } - ts_info("gesture switch: OFF"); - ts_debug("disable all gesture type"); - memset(gsx_gesture->gesture_type, 0x00, GSX_GESTURE_TYPE_LEN); - atomic_set(&gsx_gesture->registered, 0); + atomic_set(&gsx->registered, 0); return 0; } @@ -225,9 +230,10 @@ static int gsx_gesture_ist( { struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; struct goodix_ts_event gs_event = { 0 }; + int fodx, fody, overlay_area; int ret; - if (atomic_read(&cd->suspended) == 0) + if (atomic_read(&cd->suspended) == 0 || cd->gesture_type == 0) return EVT_CONTINUE; ret = hw_ops->event_handler(cd, &gs_event); @@ -241,25 +247,78 @@ static int gsx_gesture_ist( goto re_send_ges_cmd; } - if (QUERYBIT(gsx_gesture->gesture_type, gs_event.gesture_type)) { - gsx_gesture->gesture_data = gs_event.gesture_type; - /* do resume routine */ - ts_info("got valid gesture type 0x%x", gs_event.gesture_type); - input_report_key(cd->input_dev, KEY_POWER, 1); - input_sync(cd->input_dev); - input_report_key(cd->input_dev, KEY_POWER, 0); - input_sync(cd->input_dev); - goto gesture_ist_exit; - } else { - ts_info("unsupported gesture:%x", gs_event.gesture_type); + switch (gs_event.gesture_type) { + case GOODIX_GESTURE_SINGLE_TAP: + if (cd->gesture_type & GESTURE_SINGLE_TAP) { + ts_info("get SINGLE-TAP gesture"); + input_report_key(cd->input_dev, KEY_WAKEUP, 1); + // input_report_key(cd->input_dev, KEY_GOTO, 1); + input_sync(cd->input_dev); + input_report_key(cd->input_dev, KEY_WAKEUP, 0); + // input_report_key(cd->input_dev, KEY_GOTO, 0); + input_sync(cd->input_dev); + } else { + ts_debug("not enable SINGLE-TAP"); + } + break; + case GOODIX_GESTURE_DOUBLE_TAP: + if (cd->gesture_type & GESTURE_DOUBLE_TAP) { + ts_info("get DOUBLE-TAP gesture"); + input_report_key(cd->input_dev, KEY_WAKEUP, 1); + input_sync(cd->input_dev); + input_report_key(cd->input_dev, KEY_WAKEUP, 0); + input_sync(cd->input_dev); + } else { + ts_debug("not enable DOUBLE-TAP"); + } + break; + case GOODIX_GESTURE_FOD_DOWN: + if (cd->gesture_type & GESTURE_FOD_PRESS) { + ts_info("get FOD-DOWN gesture"); + fodx = le16_to_cpup((__le16 *)gs_event.gesture_data); + fody = le16_to_cpup( + (__le16 *)(gs_event.gesture_data + 2)); + overlay_area = gs_event.gesture_data[4]; + ts_debug("fodx:%d fody:%d overlay_area:%d", fodx, fody, + overlay_area); + input_report_key(cd->input_dev, BTN_TOUCH, 1); + input_mt_slot(cd->input_dev, 0); + input_mt_report_slot_state( + cd->input_dev, MT_TOOL_FINGER, 1); + input_report_abs( + cd->input_dev, ABS_MT_POSITION_X, fodx); + input_report_abs( + cd->input_dev, ABS_MT_POSITION_Y, fody); + input_report_abs(cd->input_dev, ABS_MT_WIDTH_MAJOR, + overlay_area); + input_sync(cd->input_dev); + } else { + ts_debug("not enable FOD-DOWN"); + } + break; + case GOODIX_GESTURE_FOD_UP: + if (cd->gesture_type & GESTURE_FOD_PRESS) { + ts_info("get FOD-UP gesture"); + // fodx = le16_to_cpup((__le16 *)gs_event.gesture_data); + // fody = le16_to_cpup((__le16 *)(gs_event.gesture_data + // + 2)); overlay_area = gs_event.gesture_data[4]; + input_report_key(cd->input_dev, BTN_TOUCH, 0); + input_mt_slot(cd->input_dev, 0); + input_mt_report_slot_state( + cd->input_dev, MT_TOOL_FINGER, 0); + input_sync(cd->input_dev); + } else { + ts_debug("not enable FOD-UP"); + } + break; + default: + ts_err("not support gesture type[%02X]", gs_event.gesture_type); + break; } re_send_ges_cmd: if (hw_ops->gesture(cd, 0)) ts_info("warning: failed re_send gesture cmd"); -gesture_ist_exit: - if (!cd->tools_ctrl_sync) - hw_ops->after_event_handler(cd); return EVT_CANCEL_IRQEVT; } @@ -277,11 +336,14 @@ static int gsx_gesture_before_suspend( int ret; const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; + if (cd->gesture_type == 0) + return EVT_CONTINUE; + ret = hw_ops->gesture(cd, 0); if (ret) ts_err("failed enter gesture mode"); else - ts_info("enter gesture mode"); + ts_info("enter gesture mode, type[0x%02X]", cd->gesture_type); hw_ops->irq_enable(cd, true); enable_irq_wake(cd->irq); @@ -294,7 +356,9 @@ static int gsx_gesture_before_resume( { const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; - hw_ops->irq_enable(cd, false); + if (cd->gesture_type == 0) + return EVT_CONTINUE; + disable_irq_wake(cd->irq); hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS); @@ -326,7 +390,6 @@ int gesture_module_init(void) gsx_gesture->module.priv_data = gsx_gesture; atomic_set(&gsx_gesture->registered, 0); - rwlock_init(&gsx_gesture->rwlock); /* gesture sysfs init */ ret = kobject_init_and_add( @@ -350,6 +413,7 @@ int gesture_module_init(void) } module_initialized = true; + goodix_register_ext_module_no_wait(&gsx_gesture->module); ts_info("gesture module init success"); return 0; @@ -368,7 +432,7 @@ void gesture_module_exit(void) if (!module_initialized) return; - goodix_gesture_enable(0); + goodix_unregister_ext_module(&gsx_gesture->module); /* deinit sysfs */ for (i = 0; i < ARRAY_SIZE(gesture_attrs); i++) diff --git a/goodix_ts_inspect.c b/goodix_ts_inspect.c index 6b6e942..125db6b 100644 --- a/goodix_ts_inspect.c +++ b/goodix_ts_inspect.c @@ -25,7 +25,7 @@ /* test config */ #define TOTAL_FRAME_NUM 1 /* rawdata test frames */ #define NOISEDATA_TEST_TIMES 1 /* noise test frames */ -#define SAVE_IN_CSV +// #define SAVE_IN_CSV #define GOODIX_RESULT_SAVE_PATH "/vendor/etc/Test_Data.csv" #define GOODIX_TEST_FILE_NAME "goodix" @@ -108,6 +108,17 @@ #define DRV_SEN_SELFCODE_REG_BRD 0x14556 #define DIFF_CODE_DATA_REG_BRD 0x14D00 +/* nottingham */ +#define MAX_DRV_NUM_NOT 17 +#define MAX_SEN_NUM_NOT 35 +#define SHORT_TEST_TIME_REG_NOT 0x1479E +#define SHORT_TEST_STATUS_REG_NOT 0x13400 +#define SHORT_TEST_RESULT_REG_NOT 0x13408 +#define DRV_DRV_SELFCODE_REG_NOT 0x13446 +#define SEN_SEN_SELFCODE_REG_NOT 0x136EE +#define DRV_SEN_SELFCODE_REG_NOT 0x14152 +#define DIFF_CODE_DATA_REG_NOT 0x14734 + #define ABS(val) ((val < 0) ? -(val) : val) #define MAX(a, b) ((a > b) ? a : b) @@ -200,6 +211,14 @@ static u8 brl_d_sen_map[] = { 39, }; +/* nottingham drv-sen map */ +static u8 not_drv_map[] = { 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51 }; + +static u8 not_sen_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34 }; + typedef struct __attribute__((packed)) { u8 result; u8 drv_drv_num; @@ -278,6 +297,23 @@ struct params_info_t params_brd = { DFT_DIFFCODE_SHORT_THRESHOLD_BRD, }; +struct params_info_t params_not = { + MAX_DRV_NUM_NOT, + MAX_SEN_NUM_NOT, + not_drv_map, + not_sen_map, + SHORT_TEST_TIME_REG_NOT, + SHORT_TEST_STATUS_REG_NOT, + SHORT_TEST_RESULT_REG_NOT, + DRV_DRV_SELFCODE_REG_NOT, + SEN_SEN_SELFCODE_REG_NOT, + DRV_SEN_SELFCODE_REG_NOT, + DIFF_CODE_DATA_REG_NOT, + 0, + 0, + 0, +}; + struct ts_test_params { bool test_items[MAX_TEST_ITEMS]; @@ -354,18 +390,22 @@ static int cal_cha_to_cha_res(struct goodix_ts_test *ts_test, int v1, int v2) return (v1 - v2) * 63 / v2; else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_B) return (v1 - v2) * 74 / v2 + 20; - else + else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) return (v1 / v2 - 1) * 70 + 59; + else + return (v1 / v2 - 1) * 55 + 45; } static int cal_cha_to_avdd_res(struct goodix_ts_test *ts_test, int v1, int v2) { if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_A) - return 125 * 1024 * (100 * v2 - 125) * 40 / (10000 * v1) - 40; + return 64 * (2 * v2 - 25) * 40 / v1 - 40; else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_B) - return 125 * 1024 * (100 * v2 - 125) * 99 / (10000 * v1) - 60; + return 64 * (2 * v2 - 25) * 99 / v1 - 60; + else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) + return 64 * (2 * v2 - 25) * 93 / v1 - 20; else - return 125 * 1024 * (100 * v2 - 125) * 93 / (10000 * v1) - 20; + return 64 * (2 * v2 - 25) * 76 / v1 - 15; } static int cal_cha_to_gnd_res(struct goodix_ts_test *ts_test, int v) @@ -374,8 +414,10 @@ static int cal_cha_to_gnd_res(struct goodix_ts_test *ts_test, int v) return 64148 / v - 40; else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_B) return 150500 / v - 60; - else + else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) return 145000 / v - 15; + else + return 120000 / v - 16; } static int ts_test_reset(struct goodix_ts_test *ts_test, u32 delay_ms) @@ -592,8 +634,10 @@ static void goodix_init_params(struct goodix_ts_test *ts_test) test_params->params_info = ¶ms_bra; else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_B) test_params->params_info = ¶ms_brb; - else + else if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) test_params->params_info = ¶ms_brd; + else if (ts_test->ts->bus->ic_type == IC_TYPE_NOTTINGHAM) + test_params->params_info = ¶ms_not; } static int goodix_init_testlimits(struct goodix_ts_test *ts_test) @@ -805,7 +849,8 @@ static int goodix_short_test_prepare(struct goodix_ts_test *ts_test) struct goodix_ts_cmd tmp_cmd; struct goodix_fw_version fw_ver; int ret; - int retry = 3; + int retry; + int resend = 3; u8 status; ts_info("short test prepare IN"); @@ -813,12 +858,14 @@ static int goodix_short_test_prepare(struct goodix_ts_test *ts_test) tmp_cmd.len = 4; tmp_cmd.cmd = INSPECT_FW_SWITCH_CMD; +resend_cmd: ret = ts_test_send_cmd(ts_test, &tmp_cmd); if (ret < 0) { ts_err("send test mode failed"); return ret; } + retry = 3; while (retry--) { msleep(40); if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_A) { @@ -843,6 +890,11 @@ static int goodix_short_test_prepare(struct goodix_ts_test *ts_test) } } + if (resend--) { + ts_test_reset(ts_test, 100); + goto resend_cmd; + } + return -EINVAL; } @@ -1204,22 +1256,24 @@ static int gdix_check_resistance_to_gnd( u16 r_th = 0, avdd_value = 0; u16 chn_id_tmp = 0; u8 pin_num = 0; + unsigned short short_type; struct goodix_ts_test *ts_test = container_of(test_params, struct goodix_ts_test, test_params); int max_drv_num = test_params->params_info->max_drv_num; int max_sen_num = test_params->params_info->max_sen_num; avdd_value = test_params->avdd_value; - if (adc_signal == 0 || adc_signal == 0x8000) - adc_signal |= 1; + short_type = adc_signal & 0x8000; + adc_signal &= ~0x8000; + if (adc_signal == 0) + adc_signal = 1; - if ((adc_signal & 0x8000) == 0) { + if (short_type == 0) { /* short to GND */ r = cal_cha_to_gnd_res(ts_test, adc_signal); } else { /* short to VDD */ - r = cal_cha_to_avdd_res( - ts_test, adc_signal & ~0x8000, avdd_value); + r = cal_cha_to_avdd_res(ts_test, adc_signal, avdd_value); } if (pos < max_drv_num) @@ -1236,11 +1290,11 @@ static int gdix_check_resistance_to_gnd( if (r < r_th) { pin_num = map_die2pin(test_params, chn_id_tmp); goodix_save_short_res(test_params, pin_num, - (adc_signal & 0x8000) ? CHN_VDD : CHN_GND, r); + short_type ? CHN_VDD : CHN_GND, r); ts_err("%s%d shortcircut to %s,R=%ldK,R_Threshold=%dK", (pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", (pin_num & ~DRV_CHANNEL_FLAG), - (adc_signal & 0x8000) ? "VDD" : "GND", r, r_th); + short_type ? "VDD" : "GND", r, r_th); return -EINVAL; } @@ -1490,7 +1544,8 @@ static int goodix_cap_test_prepare(struct goodix_ts_test *ts_test) ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; /* switch rawdata mode */ - if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) { + if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D || + ts_test->ts->bus->ic_type == IC_TYPE_NOTTINGHAM) { temp_cmd.cmd = 0x90; temp_cmd.data[0] = 0x81; temp_cmd.len = 5; @@ -1529,7 +1584,8 @@ static int goodix_cache_rawdata(struct goodix_ts_test *ts_test) u32 data_addr = ts_test->test_params.rawdata_addr; u32 flag_addr = ts_test->ts->ic_info.misc.touch_data_addr; - if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D) + if (ts_test->ts->bus->ic_type == IC_TYPE_BERLIN_D || + ts_test->ts->bus->ic_type == IC_TYPE_NOTTINGHAM) flag_addr = ts_test->ts->ic_info.misc.frame_data_addr; for (i = 0; i < TOTAL_FRAME_NUM; i++) { @@ -1552,7 +1608,8 @@ static int goodix_cache_rawdata(struct goodix_ts_test *ts_test) return -EAGAIN; } - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) { + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) { ret = ts_test_read(ts_test, flag_addr, frame_buf, sizeof(frame_buf)); if (ret < 0) @@ -1651,7 +1708,8 @@ static int goodix_cache_self_rawdata(struct goodix_ts_test *ts_test) unsigned char frame_buf[GOODIX_MAX_FRAMEDATA_LEN]; unsigned char *cur_ptr; - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) { + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) { ret = ts_test_read( ts_test, flag_addr, frame_buf, sizeof(frame_buf)); if (ret < 0) @@ -1705,7 +1763,8 @@ static int goodix_cache_noisedata(struct goodix_ts_test *ts_test) u32 data_addr = ts_test->test_params.noisedata_addr; u32 flag_addr = ts_test->ts->ic_info.misc.touch_data_addr; - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) { + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) { flag_addr = ts_test->ts->ic_info.misc.frame_data_addr; temp_cmd.cmd = 0x90; temp_cmd.data[0] = 0x82; @@ -1737,7 +1796,8 @@ static int goodix_cache_noisedata(struct goodix_ts_test *ts_test) return -EAGAIN; } - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) { + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) { ret = ts_test_read(ts_test, flag_addr, frame_buf, sizeof(frame_buf)); if (ret < 0) @@ -1793,7 +1853,8 @@ static int goodix_cache_self_noisedata(struct goodix_ts_test *ts_test) unsigned char frame_buf[GOODIX_MAX_FRAMEDATA_LEN]; unsigned char *cur_ptr; - if (cd->bus->ic_type == IC_TYPE_BERLIN_D) { + if (cd->bus->ic_type == IC_TYPE_BERLIN_D || + cd->bus->ic_type == IC_TYPE_NOTTINGHAM) { ret = ts_test_read( ts_test, flag_addr, frame_buf, sizeof(frame_buf)); if (ret < 0) @@ -2323,740 +2384,750 @@ static int goodix_save_limits(struct goodix_ts_test *ts_test, struct file *fp) data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); if (!data) { - ts_err("alloc memory failed for "); return -ENOMEM; - } - bytes += sprintf(&data[bytes], "<TestItems>\n"); + bytes += sprintf(&data[bytes], "<TestItems>\n"); - /* save short result */ - if (ts_test->test_result[GTP_SHORT_TEST]) { - bytes += sprintf(&data[bytes], "<Item name=\"Short Test\">\n"); - bytes += sprintf(&data[bytes], "<ShortNum>%d</ShortNum>\n", - ts_test->short_res.short_num); - for (i = 0; i < ts_test->short_res.short_num; i++) { - chn1 = ts_test->short_res.short_msg[4 * i]; - chn2 = ts_test->short_res.short_msg[4 * i + 1]; - r = (ts_test->short_res.short_msg[4 * i + 2] << 8) + - ts_test->short_res.short_msg[4 * i + 3]; - if (chn1 == CHN_VDD) - bytes += sprintf(&data[bytes], - "<ShortMess Chn1=\"VDD\" "); - else if (chn1 == CHN_GND) - bytes += sprintf(&data[bytes], - "<ShortMess Chn1=\"GND\" "); - else if (chn1 & DRV_CHANNEL_FLAG) - bytes += sprintf(&data[bytes], - "<ShortMess Chn1=\"Tx%d\" ", - chn1 & 0x7f); - else - bytes += sprintf(&data[bytes], - "<ShortMess Chn1=\"Rx%d\" ", - chn1 & 0x7f); - if (chn2 == CHN_VDD) - bytes += sprintf(&data[bytes], - "Chn2=\"VDD\" ShortResistor= \"%dKom\"/>\n", - r); - else if (chn2 == CHN_GND) - bytes += sprintf(&data[bytes], - "Chn2=\"GND\" ShortResistor= \"%dKom\"/>\n", - r); - else if (chn2 & DRV_CHANNEL_FLAG) - bytes += sprintf(&data[bytes], - "Chn2=\"Tx%d\" ShortResistor= \"%dKom\"/>\n", - chn2 & 0x7f, r); - else - bytes += sprintf(&data[bytes], - "Chn2=\"Rx%d\" ShortResistor= \"%dKom\"/>\n", - chn2 & 0x7f, r); - } - bytes += sprintf(&data[bytes], "</Item>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("short res write fail."); - goto save_end; + /* save short result */ + if (ts_test->test_result[GTP_SHORT_TEST]) { + bytes += sprintf( + &data[bytes], "<Item name=\"Short Test\">\n"); + bytes += sprintf(&data[bytes], + "<ShortNum>%d</ShortNum>\n", + ts_test->short_res.short_num); + for (i = 0; i < ts_test->short_res.short_num; i++) { + chn1 = ts_test->short_res.short_msg[4 * i]; + chn2 = ts_test->short_res.short_msg[4 * i + 1]; + r = (ts_test->short_res.short_msg[4 * i + 2] + << 8) + + ts_test->short_res.short_msg[4 * i + 3]; + if (chn1 == CHN_VDD) + bytes += sprintf(&data[bytes], + "<ShortMess Chn1=\"VDD\" "); + else if (chn1 == CHN_GND) + bytes += sprintf(&data[bytes], + "<ShortMess Chn1=\"GND\" "); + else if (chn1 & DRV_CHANNEL_FLAG) + bytes += sprintf(&data[bytes], + "<ShortMess Chn1=\"Tx%d\" ", + chn1 & 0x7f); + else + bytes += sprintf(&data[bytes], + "<ShortMess Chn1=\"Rx%d\" ", + chn1 & 0x7f); + if (chn2 == CHN_VDD) + bytes += sprintf(&data[bytes], + "Chn2=\"VDD\" ShortResistor= \"%dKom\"/>\n", + r); + else if (chn2 == CHN_GND) + bytes += sprintf(&data[bytes], + "Chn2=\"GND\" ShortResistor= \"%dKom\"/>\n", + r); + else if (chn2 & DRV_CHANNEL_FLAG) + bytes += sprintf(&data[bytes], + "Chn2=\"Tx%d\" ShortResistor= \"%dKom\"/>\n", + chn2 & 0x7f, r); + else + bytes += sprintf(&data[bytes], + "Chn2=\"Rx%d\" ShortResistor= \"%dKom\"/>\n", + chn2 & 0x7f, r); + } + bytes += sprintf(&data[bytes], "</Item>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("short res write fail."); + goto save_end; + } + bytes = 0; } - bytes = 0; - } - - /* rawdata max limit */ - bytes += sprintf(&data[bytes], "<Item name=\"Rawdata Test Sets\">\n"); - bytes += sprintf(&data[bytes], "<TotalFrameCnt>%d</TotalFrameCnt>\n", - TOTAL_FRAME_NUM); - bytes += sprintf(&data[bytes], "<MaxRawLimit>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->test_params.max_limits[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</MaxRawLimit>\n"); - /* BeyondRawdataUpperLimit */ - bytes += sprintf(&data[bytes], "<BeyondRawdataUpperLimitCnt>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->open_res.beyond_max_limit_cnt[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</BeyondRawdataUpperLimitCnt>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("rawdata limit write failed"); - goto save_end; - } - bytes = 0; - /* rawdata min limit */ - bytes += sprintf(&data[bytes], "<MinRawLimit>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->test_params.min_limits[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</MinRawLimit>\n"); - /* BeyondRawdataLower limit */ - bytes += sprintf(&data[bytes], "<BeyondRawdataLowerLimitCnt>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->open_res.beyond_min_limit_cnt[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</BeyondRawdataLowerLimitCnt>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("rawdata limit write failed"); - goto save_end; - } - bytes = 0; - - /* Max Accord limit */ - bytes += sprintf(&data[bytes], "<MaxAccordLimit>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->test_params.deviation_limits[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</MaxAccordLimit>\n"); - /* BeyondAccordLimitCnt */ - bytes += sprintf(&data[bytes], "<BeyondAccordLimitCnt>\n"); - for (i = 0; i < tx * rx; i++) { - bytes += sprintf(&data[bytes], "%d,", - ts_test->open_res.beyond_accord_limit_cnt[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); - } - bytes += sprintf(&data[bytes], "</BeyondAccordLimitCnt>\n"); - bytes += sprintf(&data[bytes], "</Item>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("rawdata limit write failed"); - goto save_end; - } - bytes = 0; - - /* save noise limit */ - if (ts_test->test_result[GTP_NOISE_TEST]) { + /* rawdata max limit */ bytes += sprintf( - &data[bytes], "<Item name=\"Diffdata Test Sets\">\n"); - bytes += sprintf(&data[bytes], - "<TotalFrameCnt>%d</TotalFrameCnt>\n", - NOISEDATA_TEST_TIMES); - bytes += sprintf(&data[bytes], - "<MaxJitterLimit>%d</MaxJitterLimit>\n", - ts_test->test_params.noise_threshold); - bytes += sprintf(&data[bytes], "</Item>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("noise limit write failed"); - goto save_end; - } - bytes = 0; - } - - /* save self rawdata limit */ - if (ts_test->test_result[GTP_SELFCAP_TEST]) { + &data[bytes], "<Item name=\"Rawdata Test Sets\">\n"); bytes += sprintf(&data[bytes], - "<Item name=\"Self Rawdata Test Sets\">\n"); - bytes += sprintf( - &data[bytes], "<TotalFrameCnt>1</TotalFrameCnt>\n"); + "<TotalFrameCnt>%d</TotalFrameCnt>\n", TOTAL_FRAME_NUM); bytes += sprintf(&data[bytes], "<MaxRawLimit>\n"); - for (i = 0; i < tx + rx; i++) { + for (i = 0; i < tx * rx; i++) { bytes += sprintf(&data[bytes], "%d,", - ts_test->test_params.self_max_limits[i]); + ts_test->test_params.max_limits[i]); if ((i + 1) % tx == 0) bytes += sprintf(&data[bytes], "\n"); } - if ((tx + rx) % tx != 0) - bytes += sprintf(&data[bytes], "\n"); bytes += sprintf(&data[bytes], "</MaxRawLimit>\n"); - bytes += sprintf(&data[bytes], "<MinRawLimit>\n"); - for (i = 0; i < tx + rx; i++) { + /* BeyondRawdataUpperLimit */ + bytes += + sprintf(&data[bytes], "<BeyondRawdataUpperLimitCnt>\n"); + for (i = 0; i < tx * rx; i++) { bytes += sprintf(&data[bytes], "%d,", - ts_test->test_params.self_min_limits[i]); + ts_test->open_res.beyond_max_limit_cnt[i]); if ((i + 1) % tx == 0) bytes += sprintf(&data[bytes], "\n"); } - if ((tx + rx) % tx != 0) - bytes += sprintf(&data[bytes], "\n"); - bytes += sprintf(&data[bytes], "</MinRawLimit>\n"); - bytes += sprintf(&data[bytes], "</Item>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("self rawdata limit write failed"); - goto save_end; - } - bytes = 0; - } - - /* save selfnoise limit */ - if (ts_test->test_result[GTP_SELFNOISE_TEST]) { - bytes += sprintf(&data[bytes], - "<Item name=\"Self Diffdata Test Sets\">\n"); bytes += sprintf( - &data[bytes], "<TotalFrameCnt>1</TotalFrameCnt>\n"); - bytes += sprintf(&data[bytes], - "<MaxJitterLimit>%d</MaxJitterLimit>\n", - ts_test->test_params.self_noise_threshold); - bytes += sprintf(&data[bytes], "</Item>\n"); + &data[bytes], "</BeyondRawdataUpperLimitCnt>\n"); ret = fs_write(data, bytes, fp); if (ret < 0) { - ts_err("raw limit write failed"); + ts_err("rawdata limit write failed"); goto save_end; } bytes = 0; - } - bytes += sprintf(&data[bytes], "</TestItems>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("limit write fail."); - -save_end: - kfree(data); - return ret; -} - -static int goodix_save_rawdata(struct goodix_ts_test *ts_test, struct file *fp) -{ - int i; - int j; - int ret; - int bytes = 0; - s16 stat_result[3]; - char *data = NULL; - int tx = ts_test->test_params.drv_num; - int rx = ts_test->test_params.sen_num; - int len = tx * rx; - - data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); - if (!data) { - ts_err("alloc memory failed for "); - return -ENOMEM; - } - - bytes += sprintf(&data[bytes], "<RawDataRecord>\n"); - for (i = 0; i < TOTAL_FRAME_NUM; i++) { - goodix_data_cal(ts_test->rawdata[i].data, len, stat_result); - bytes += sprintf(&data[bytes], - "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", - i, len, stat_result[1], stat_result[2], stat_result[0]); - for (j = 0; j < len; j++) { + /* rawdata min limit */ + bytes += sprintf(&data[bytes], "<MinRawLimit>\n"); + for (i = 0; i < tx * rx; i++) { bytes += sprintf(&data[bytes], "%d,", - ts_test->rawdata[i].data[j]); - if ((j + 1) % tx == 0) + ts_test->test_params.min_limits[i]); + if ((i + 1) % tx == 0) bytes += sprintf(&data[bytes], "\n"); } - bytes += sprintf(&data[bytes], "</DataContent>\n"); - goodix_data_cal(ts_test->accord_arr[i].data, len, stat_result); - bytes += sprintf(&data[bytes], - "<RawAccord No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", - i, len, stat_result[1], stat_result[2], stat_result[0]); - for (j = 0; j < len; j++) { + bytes += sprintf(&data[bytes], "</MinRawLimit>\n"); + /* BeyondRawdataLower limit */ + bytes += + sprintf(&data[bytes], "<BeyondRawdataLowerLimitCnt>\n"); + for (i = 0; i < tx * rx; i++) { bytes += sprintf(&data[bytes], "%d,", - ts_test->accord_arr[i].data[j]); - if ((j + 1) % tx == 0) + ts_test->open_res.beyond_min_limit_cnt[i]); + if ((i + 1) % tx == 0) bytes += sprintf(&data[bytes], "\n"); } - bytes += sprintf(&data[bytes], "</RawAccord>\n"); + bytes += sprintf( + &data[bytes], "</BeyondRawdataLowerLimitCnt>\n"); ret = fs_write(data, bytes, fp); if (ret < 0) { - ts_err("rawdata write fail."); + ts_err("rawdata limit write failed"); goto save_end; } bytes = 0; - } - - bytes += sprintf(&data[bytes], "</RawDataRecord>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("rawdata write fail."); - -save_end: - kfree(data); - return ret; -} -static int goodix_save_noise_data( - struct goodix_ts_test *ts_test, struct file *fp) -{ - int i; - int j; - int ret = 0; - int bytes = 0; - s16 stat_result[3]; - char *data = NULL; - int tx = ts_test->test_params.drv_num; - int rx = ts_test->test_params.sen_num; - int len = tx * rx; - - data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); - if (!data) { - ts_err("alloc memory failed for "); - return -ENOMEM; - } - - bytes += sprintf(&data[bytes], "<DiffDataRecord>\n"); - for (i = 0; i < NOISEDATA_TEST_TIMES; i++) { - goodix_data_cal(ts_test->noisedata[i].data, len, stat_result); - bytes += sprintf(&data[bytes], - "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", - i, len, stat_result[1], stat_result[2], stat_result[0]); - for (j = 0; j < len; j++) { + /* Max Accord limit */ + bytes += sprintf(&data[bytes], "<MaxAccordLimit>\n"); + for (i = 0; i < tx * rx; i++) { bytes += sprintf(&data[bytes], "%d,", - ts_test->noisedata[i].data[j]); - if ((j + 1) % tx == 0) + ts_test->test_params.deviation_limits[i]); + if ((i + 1) % tx == 0) bytes += sprintf(&data[bytes], "\n"); } - bytes += sprintf(&data[bytes], "</DataContent>\n"); + bytes += sprintf(&data[bytes], "</MaxAccordLimit>\n"); + /* BeyondAccordLimitCnt */ + bytes += sprintf(&data[bytes], "<BeyondAccordLimitCnt>\n"); + for (i = 0; i < tx * rx; i++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->open_res.beyond_accord_limit_cnt[i]); + if ((i + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + bytes += sprintf(&data[bytes], "</BeyondAccordLimitCnt>\n"); + bytes += sprintf(&data[bytes], "</Item>\n"); ret = fs_write(data, bytes, fp); if (ret < 0) { - ts_err("noisedata write fail."); + ts_err("rawdata limit write failed"); goto save_end; } bytes = 0; - } - bytes += sprintf(&data[bytes], "</DiffDataRecord>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("noisedata write fail."); + /* save noise limit */ + if (ts_test->test_result[GTP_NOISE_TEST]) { + bytes += sprintf(&data[bytes], + "<Item name=\"Diffdata Test Sets\">\n"); + bytes += sprintf(&data[bytes], + "<TotalFrameCnt>%d</TotalFrameCnt>\n", + NOISEDATA_TEST_TIMES); + bytes += sprintf(&data[bytes], + "<MaxJitterLimit>%d</MaxJitterLimit>\n", + ts_test->test_params.noise_threshold); + bytes += sprintf(&data[bytes], "</Item>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("noise limit write failed"); + goto save_end; + } + bytes = 0; + } -save_end: - kfree(data); - return ret; -} + /* save self rawdata limit */ + if (ts_test->test_result[GTP_SELFCAP_TEST]) { + bytes += sprintf(&data[bytes], + "<Item name=\"Self Rawdata Test Sets\">\n"); + bytes += sprintf(&data[bytes], + "<TotalFrameCnt>1</TotalFrameCnt>\n"); + bytes += sprintf(&data[bytes], "<MaxRawLimit>\n"); + for (i = 0; i < tx + rx; i++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->test_params + .self_max_limits[i]); + if ((i + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + if ((tx + rx) % tx != 0) + bytes += sprintf(&data[bytes], "\n"); + bytes += sprintf(&data[bytes], "</MaxRawLimit>\n"); + bytes += sprintf(&data[bytes], "<MinRawLimit>\n"); + for (i = 0; i < tx + rx; i++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->test_params + .self_min_limits[i]); + if ((i + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + if ((tx + rx) % tx != 0) + bytes += sprintf(&data[bytes], "\n"); + bytes += sprintf(&data[bytes], "</MinRawLimit>\n"); + bytes += sprintf(&data[bytes], "</Item>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("self rawdata limit write failed"); + goto save_end; + } + bytes = 0; + } -static int goodix_save_self_data(struct goodix_ts_test *ts_test, - struct file *fp, s16 *src_data, u8 *title, int len) -{ - int i; - int ret = 0; - s32 bytes = 0; - char *data; - s16 stat_result[3]; - int tx = ts_test->test_params.drv_num; + /* save selfnoise limit */ + if (ts_test->test_result[GTP_SELFNOISE_TEST]) { + bytes += sprintf(&data[bytes], + "<Item name=\"Self Diffdata Test Sets\">\n"); + bytes += sprintf(&data[bytes], + "<TotalFrameCnt>1</TotalFrameCnt>\n"); + bytes += sprintf(&data[bytes], + "<MaxJitterLimit>%d</MaxJitterLimit>\n", + ts_test->test_params.self_noise_threshold); + bytes += sprintf(&data[bytes], "</Item>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("raw limit write failed"); + goto save_end; + } + bytes = 0; + } - data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); - if (!data) { - ts_err("alloc memory failed for "); - return -ENOMEM; - } + bytes += sprintf(&data[bytes], "</TestItems>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) + ts_err("limit write fail."); - bytes += sprintf(&data[bytes], "<%s>\n", title); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("rawdata write fail."); - goto save_end; + save_end: + kfree(data); + return ret; } - bytes = 0; - goodix_data_cal(src_data, len, stat_result); - bytes += sprintf(&data[bytes], - "<DataContent No.=\"0\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", - len, stat_result[1], stat_result[2], stat_result[0]); - for (i = 0; i < len; i++) { - bytes += sprintf(&data[bytes], "%d,", src_data[i]); - if ((i + 1) % tx == 0) - bytes += sprintf(&data[bytes], "\n"); + static int goodix_save_rawdata( + struct goodix_ts_test * ts_test, struct file * fp) + { + int i; + int j; + int ret; + int bytes = 0; + s16 stat_result[3]; + char *data = NULL; + int tx = ts_test->test_params.drv_num; + int rx = ts_test->test_params.sen_num; + int len = tx * rx; + + data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); + if (!data) + return -ENOMEM; + + bytes += sprintf(&data[bytes], "<RawDataRecord>\n"); + for (i = 0; i < TOTAL_FRAME_NUM; i++) { + goodix_data_cal( + ts_test->rawdata[i].data, len, stat_result); + bytes += sprintf(&data[bytes], + "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, len, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < len; j++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->rawdata[i].data[j]); + if ((j + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + bytes += sprintf(&data[bytes], "</DataContent>\n"); + goodix_data_cal( + ts_test->accord_arr[i].data, len, stat_result); + bytes += sprintf(&data[bytes], + "<RawAccord No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, len, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < len; j++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->accord_arr[i].data[j]); + if ((j + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + bytes += sprintf(&data[bytes], "</RawAccord>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("rawdata write fail."); + goto save_end; + } + bytes = 0; + } + + bytes += sprintf(&data[bytes], "</RawDataRecord>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) + ts_err("rawdata write fail."); + + save_end: + kfree(data); + return ret; } - if (len % tx != 0) - bytes += sprintf(&data[bytes], "\n"); - bytes += sprintf(&data[bytes], "</DataContent>\n"); - bytes += sprintf(&data[bytes], "</%s>\n", title); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("rawdata write fail."); -save_end: - kfree(data); - return ret; -} + static int goodix_save_noise_data( + struct goodix_ts_test * ts_test, struct file * fp) + { + int i; + int j; + int ret = 0; + int bytes = 0; + s16 stat_result[3]; + char *data = NULL; + int tx = ts_test->test_params.drv_num; + int rx = ts_test->test_params.sen_num; + int len = tx * rx; + + data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); + if (!data) + return -ENOMEM; + + bytes += sprintf(&data[bytes], "<DiffDataRecord>\n"); + for (i = 0; i < NOISEDATA_TEST_TIMES; i++) { + goodix_data_cal( + ts_test->noisedata[i].data, len, stat_result); + bytes += sprintf(&data[bytes], + "<DataContent No.=\"%d\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + i, len, stat_result[1], stat_result[2], + stat_result[0]); + for (j = 0; j < len; j++) { + bytes += sprintf(&data[bytes], "%d,", + ts_test->noisedata[i].data[j]); + if ((j + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + bytes += sprintf(&data[bytes], "</DataContent>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("noisedata write fail."); + goto save_end; + } + bytes = 0; + } -static int goodix_save_data(struct goodix_ts_test *ts_test, struct file *fp) -{ - int ret; - int bytes = 0; - char *data = NULL; + bytes += sprintf(&data[bytes], "</DiffDataRecord>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) + ts_err("noisedata write fail."); - data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); - if (!data) { - ts_err("alloc memory failed for "); - return -ENOMEM; + save_end: + kfree(data); + return ret; } - bytes += sprintf(&data[bytes], "<DataRecord>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) { - ts_err("rawdata record label failed"); - goto save_end; - } - bytes = 0; + static int goodix_save_self_data(struct goodix_ts_test * ts_test, + struct file * fp, s16 * src_data, u8 * title, int len) + { + int i; + int ret = 0; + s32 bytes = 0; + char *data; + s16 stat_result[3]; + int tx = ts_test->test_params.drv_num; - ret = goodix_save_rawdata(ts_test, fp); - if (ret < 0) - goto save_end; + data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); + if (!data) + return -ENOMEM; - if (ts_test->test_result[GTP_NOISE_TEST]) { - ret = goodix_save_noise_data(ts_test, fp); - if (ret < 0) + bytes += sprintf(&data[bytes], "<%s>\n", title); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("rawdata write fail."); goto save_end; - } + } + bytes = 0; - if (ts_test->test_result[GTP_SELFCAP_TEST]) { - ret = goodix_save_self_data(ts_test, fp, - ts_test->self_rawdata.data, "selfDataRecord", - ts_test->self_rawdata.size); + goodix_data_cal(src_data, len, stat_result); + bytes += sprintf(&data[bytes], + "<DataContent No.=\"0\" DataCount=\"%d\" Maximum=\"%d\" Minimum=\"%d\" Average=\"%d\">\n", + len, stat_result[1], stat_result[2], stat_result[0]); + for (i = 0; i < len; i++) { + bytes += sprintf(&data[bytes], "%d,", src_data[i]); + if ((i + 1) % tx == 0) + bytes += sprintf(&data[bytes], "\n"); + } + if (len % tx != 0) + bytes += sprintf(&data[bytes], "\n"); + bytes += sprintf(&data[bytes], "</DataContent>\n"); + bytes += sprintf(&data[bytes], "</%s>\n", title); + ret = fs_write(data, bytes, fp); if (ret < 0) - goto save_end; - } + ts_err("rawdata write fail."); - if (ts_test->test_result[GTP_SELFNOISE_TEST]) { - ret = goodix_save_self_data(ts_test, fp, - ts_test->self_noisedata.data, "selfDiffDataRecord", - ts_test->self_noisedata.size); - if (ret < 0) - goto save_end; + save_end: + kfree(data); + return ret; } - bytes += sprintf(&data[bytes], "</DataRecord>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("rawdata data record label fail."); + static int goodix_save_data( + struct goodix_ts_test * ts_test, struct file * fp) + { + int ret; + int bytes = 0; + char *data = NULL; -save_end: - kfree(data); - return ret; -} + data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); + if (!data) + return -ENOMEM; -/* save end tag in csv file */ -static int goodix_save_tail(struct goodix_ts_test *ts_test, struct file *fp) -{ - int ret = 0; - int bytes = 0; - char *data = NULL; + bytes += sprintf(&data[bytes], "<DataRecord>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) { + ts_err("rawdata record label failed"); + goto save_end; + } + bytes = 0; - data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); - if (!data) { - ts_err("alloc memory failed for "); - return -ENOMEM; - } + ret = goodix_save_rawdata(ts_test, fp); + if (ret < 0) + goto save_end; - bytes += sprintf(&data[bytes], "</TESTLOG>\n"); - ret = fs_write(data, bytes, fp); - if (ret < 0) - ts_err("tail write failed"); + if (ts_test->test_result[GTP_NOISE_TEST]) { + ret = goodix_save_noise_data(ts_test, fp); + if (ret < 0) + goto save_end; + } - kfree(data); - return ret; -} + if (ts_test->test_result[GTP_SELFCAP_TEST]) { + ret = goodix_save_self_data(ts_test, fp, + ts_test->self_rawdata.data, "selfDataRecord", + ts_test->self_rawdata.size); + if (ret < 0) + goto save_end; + } -static void goodix_save_result_data(struct goodix_ts_test *ts_test) -{ - int ret = 0; - char save_path[100]; - struct file *fp = NULL; + if (ts_test->test_result[GTP_SELFNOISE_TEST]) { + ret = goodix_save_self_data(ts_test, fp, + ts_test->self_noisedata.data, + "selfDiffDataRecord", + ts_test->self_noisedata.size); + if (ret < 0) + goto save_end; + } - /* format result file */ - sprintf(save_path, GOODIX_RESULT_SAVE_PATH); - ts_info("save result IN, file_name:%s", save_path); + bytes += sprintf(&data[bytes], "</DataRecord>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) + ts_err("rawdata data record label fail."); - fp = filp_open(save_path, O_CREAT | O_WRONLY | O_TRUNC, 0666); - if (IS_ERR(fp)) { - ts_err("create file:%s failed, fp:%ld", save_path, PTR_ERR(fp)); - return; + save_end: + kfree(data); + return ret; } - /* save header */ - ret = goodix_save_header(ts_test, fp); - if (ret < 0) - goto save_end; + /* save end tag in csv file */ + static int goodix_save_tail( + struct goodix_ts_test * ts_test, struct file * fp) + { + int ret = 0; + int bytes = 0; + char *data = NULL; - /* save limits */ - ret = goodix_save_limits(ts_test, fp); - if (ret < 0) - goto save_end; + data = kzalloc(MAX_DATA_BUFFER, GFP_KERNEL); + if (!data) + return -ENOMEM; - /* save data */ - ret = goodix_save_data(ts_test, fp); - if (ret < 0) - goto save_end; + bytes += sprintf(&data[bytes], "</TESTLOG>\n"); + ret = fs_write(data, bytes, fp); + if (ret < 0) + ts_err("tail write failed"); - /* save tail */ - ret = goodix_save_tail(ts_test, fp); - if (ret < 0) - goto save_end; + kfree(data); + return ret; + } - ts_info("the test result save in %s", save_path); -save_end: - filp_close(fp, NULL); -} -#endif // SAVE_IN_CSV + static void goodix_save_result_data(struct goodix_ts_test * ts_test) + { + int ret = 0; + char save_path[100]; + struct file *fp = NULL; -static void goodix_put_test_result( - struct goodix_ts_test *ts_test, struct ts_rawdata_info *info) -{ - int i; - bool have_bus_error = false; - bool have_panel_error = false; - char statistics_data[STATISTICS_DATA_LEN] = { 0 }; - struct goodix_ts_core *ts = ts_test->ts; + /* format result file */ + sprintf(save_path, GOODIX_RESULT_SAVE_PATH); + ts_info("save result IN, file_name:%s", save_path); - ts_info("put test result IN"); + fp = filp_open(save_path, O_CREAT | O_WRONLY | O_TRUNC, 0666); + if (IS_ERR(fp)) { + ts_err("create file:%s failed, fp:%ld", save_path, + PTR_ERR(fp)); + return; + } - info->buff[0] = ts_test->test_params.sen_num; - info->buff[1] = ts_test->test_params.drv_num; - info->used_size = 2; - /* save rawdata to info->buff, only one frame */ - if (ts_test->rawdata[0].size) { - for (i = 0; i < ts_test->rawdata[0].size; i++) - info->buff[info->used_size + i] = - ts_test->rawdata[0].data[i]; - info->used_size += ts_test->rawdata[0].size; - } + /* save header */ + ret = goodix_save_header(ts_test, fp); + if (ret < 0) + goto save_end; - /* save noisedata to info->buff */ - if (ts_test->noisedata[0].size) { - for (i = 0; i < ts_test->noisedata[0].size; i++) - info->buff[info->used_size + i] = - ts_test->noisedata[0].data[i]; - info->used_size += ts_test->noisedata[0].size; - } + /* save limits */ + ret = goodix_save_limits(ts_test, fp); + if (ret < 0) + goto save_end; - /* save self_noisedata to info->buff */ - if (ts_test->self_noisedata.size) { - for (i = 0; i < ts_test->self_noisedata.size; i++) - info->buff[info->used_size + i] = - ts_test->self_noisedata.data[i]; - info->used_size += ts_test->self_noisedata.size; - } + /* save data */ + ret = goodix_save_data(ts_test, fp); + if (ret < 0) + goto save_end; - /* save self_rawdata to info->buff */ - if (ts_test->self_rawdata.size) { - for (i = 0; i < ts_test->self_rawdata.size; i++) - info->buff[info->used_size + i] = - ts_test->self_rawdata.data[i]; - info->used_size += ts_test->self_rawdata.size; - } + /* save tail */ + ret = goodix_save_tail(ts_test, fp); + if (ret < 0) + goto save_end; - /* check if there have bus error */ - for (i = 0; i < MAX_TEST_ITEMS; i++) { - if (ts_test->test_result[i] == SYS_SOFTWARE_REASON) - have_bus_error = true; - else if (ts_test->test_result[i] == GTP_PANEL_REASON) - have_panel_error = true; + ts_info("the test result save in %s", save_path); + save_end: + filp_close(fp, NULL); } - ts_info("Have bus error:%d", have_bus_error); - if (have_bus_error || have_panel_error) - goodix_strncat( - ts_test->test_info, "[FAIL]-", TS_RAWDATA_RESULT_MAX); - else - goodix_strncat( - ts_test->test_info, "[PASS]-", TS_RAWDATA_RESULT_MAX); - - if (have_bus_error) - goodix_strncat( - ts_test->test_info, "0F-", TS_RAWDATA_RESULT_MAX); - else - goodix_strncat( - ts_test->test_info, "0P-", TS_RAWDATA_RESULT_MAX); +#endif // SAVE_IN_CSV - for (i = 0; i < MAX_TEST_ITEMS; i++) { - /* if have tested, show result */ - if (ts_test->test_result[i]) { - if (GTP_TEST_PASS == ts_test->test_result[i]) - goodix_strncatint(ts_test->test_info, i, "%dP-", - TS_RAWDATA_RESULT_MAX); - else - goodix_strncatint(ts_test->test_info, i, "%dF-", - TS_RAWDATA_RESULT_MAX); + static void goodix_put_test_result( + struct goodix_ts_test * ts_test, struct ts_rawdata_info * info) + { + int i; + bool have_bus_error = false; + bool have_panel_error = false; + char statistics_data[STATISTICS_DATA_LEN] = { 0 }; + struct goodix_ts_core *ts = ts_test->ts; + + ts_info("put test result IN"); + + info->buff[0] = ts_test->test_params.sen_num; + info->buff[1] = ts_test->test_params.drv_num; + info->used_size = 2; + /* save rawdata to info->buff, only one frame */ + if (ts_test->rawdata[0].size) { + for (i = 0; i < ts_test->rawdata[0].size; i++) + info->buff[info->used_size + i] = + ts_test->rawdata[0].data[i]; + info->used_size += ts_test->rawdata[0].size; + } + + /* save noisedata to info->buff */ + if (ts_test->noisedata[0].size) { + for (i = 0; i < ts_test->noisedata[0].size; i++) + info->buff[info->used_size + i] = + ts_test->noisedata[0].data[i]; + info->used_size += ts_test->noisedata[0].size; } - } - /* calculate rawdata min avg max value*/ - if (ts_test->rawdata[0].size) { - goodix_data_statistics(ts_test->rawdata[0].data, - ts_test->rawdata[0].size, statistics_data, - STATISTICS_DATA_LEN); - goodix_strncat(ts_test->test_info, statistics_data, - TS_RAWDATA_RESULT_MAX); - } else { - ts_err("NO valiable rawdata"); - goodix_strncat( - ts_test->test_info, "[0,0,0]", TS_RAWDATA_RESULT_MAX); - } + /* save self_noisedata to info->buff */ + if (ts_test->self_noisedata.size) { + for (i = 0; i < ts_test->self_noisedata.size; i++) + info->buff[info->used_size + i] = + ts_test->self_noisedata.data[i]; + info->used_size += ts_test->self_noisedata.size; + } - /* calculate noisedata min avg max value*/ - if (ts_test->test_params.test_items[GTP_NOISE_TEST]) { - if (ts_test->noisedata[0].size) { - goodix_data_statistics(ts_test->noisedata[0].data, - ts_test->noisedata[0].size, statistics_data, - STATISTICS_DATA_LEN); - goodix_strncat(ts_test->test_info, statistics_data, + /* save self_rawdata to info->buff */ + if (ts_test->self_rawdata.size) { + for (i = 0; i < ts_test->self_rawdata.size; i++) + info->buff[info->used_size + i] = + ts_test->self_rawdata.data[i]; + info->used_size += ts_test->self_rawdata.size; + } + + /* check if there have bus error */ + for (i = 0; i < MAX_TEST_ITEMS; i++) { + if (ts_test->test_result[i] == SYS_SOFTWARE_REASON) + have_bus_error = true; + else if (ts_test->test_result[i] == GTP_PANEL_REASON) + have_panel_error = true; + } + ts_info("Have bus error:%d", have_bus_error); + if (have_bus_error || have_panel_error) + goodix_strncat(ts_test->test_info, "[FAIL]-", TS_RAWDATA_RESULT_MAX); - } else { - ts_err("NO valiable noisedata"); - goodix_strncat(ts_test->test_info, "[0,0,0]", + else + goodix_strncat(ts_test->test_info, "[PASS]-", TS_RAWDATA_RESULT_MAX); - } - } - /* calculate self_rawdata min avg max value*/ - if (ts_test->test_params.test_items[GTP_SELFCAP_TEST]) { - if (ts_test->self_rawdata.size) { - goodix_data_statistics(ts_test->self_rawdata.data, - ts_test->self_rawdata.size, statistics_data, - STATISTICS_DATA_LEN); - goodix_strncat(ts_test->test_info, statistics_data, + if (have_bus_error) + goodix_strncat(ts_test->test_info, "0F-", TS_RAWDATA_RESULT_MAX); - } else { - ts_err("NO valiable self_rawdata"); - goodix_strncat(ts_test->test_info, "[0,0,0]", + else + goodix_strncat(ts_test->test_info, "0P-", TS_RAWDATA_RESULT_MAX); + + for (i = 0; i < MAX_TEST_ITEMS; i++) { + /* if have tested, show result */ + if (ts_test->test_result[i]) { + if (ts_test->test_result[i] == GTP_TEST_PASS) + goodix_strncatint(ts_test->test_info, i, + "%dP-", TS_RAWDATA_RESULT_MAX); + else + goodix_strncatint(ts_test->test_info, i, + "%dF-", TS_RAWDATA_RESULT_MAX); + } } - } - /* calculate self_noisedata min avg max value*/ - if (ts_test->test_params.test_items[GTP_SELFNOISE_TEST]) { - if (ts_test->self_noisedata.size) { - goodix_data_statistics(ts_test->self_noisedata.data, - ts_test->self_noisedata.size, statistics_data, + /* calculate rawdata min avg max value*/ + if (ts_test->rawdata[0].size) { + goodix_data_statistics(ts_test->rawdata[0].data, + ts_test->rawdata[0].size, statistics_data, STATISTICS_DATA_LEN); goodix_strncat(ts_test->test_info, statistics_data, TS_RAWDATA_RESULT_MAX); } else { - ts_err("NO valiable self_noisedata"); + ts_err("NO valiable rawdata"); goodix_strncat(ts_test->test_info, "[0,0,0]", TS_RAWDATA_RESULT_MAX); } - } - goodix_strncat(ts_test->test_info, "-GT", TS_RAWDATA_RESULT_MAX); - goodix_strncat(ts_test->test_info, ts->fw_version.patch_pid, - TS_RAWDATA_RESULT_MAX); - goodix_strncat(ts_test->test_info, "\n", TS_RAWDATA_RESULT_MAX); - strncpy(info->result, ts_test->test_info, TS_RAWDATA_RESULT_MAX - 1); + /* calculate noisedata min avg max value*/ + if (ts_test->test_params.test_items[GTP_NOISE_TEST]) { + if (ts_test->noisedata[0].size) { + goodix_data_statistics( + ts_test->noisedata[0].data, + ts_test->noisedata[0].size, + statistics_data, STATISTICS_DATA_LEN); + goodix_strncat(ts_test->test_info, + statistics_data, TS_RAWDATA_RESULT_MAX); + } else { + ts_err("NO valiable noisedata"); + goodix_strncat(ts_test->test_info, "[0,0,0]", + TS_RAWDATA_RESULT_MAX); + } + } -#ifdef SAVE_IN_CSV - /* save result to file */ - goodix_save_result_data(ts_test); -#endif -} + /* calculate self_rawdata min avg max value*/ + if (ts_test->test_params.test_items[GTP_SELFCAP_TEST]) { + if (ts_test->self_rawdata.size) { + goodix_data_statistics( + ts_test->self_rawdata.data, + ts_test->self_rawdata.size, + statistics_data, STATISTICS_DATA_LEN); + goodix_strncat(ts_test->test_info, + statistics_data, TS_RAWDATA_RESULT_MAX); + } else { + ts_err("NO valiable self_rawdata"); + goodix_strncat(ts_test->test_info, "[0,0,0]", + TS_RAWDATA_RESULT_MAX); + } + } -static int goodix_do_inspect( - struct goodix_ts_core *cd, struct ts_rawdata_info *info) -{ - int ret; - struct goodix_ts_test *ts_test = NULL; + /* calculate self_noisedata min avg max value*/ + if (ts_test->test_params.test_items[GTP_SELFNOISE_TEST]) { + if (ts_test->self_noisedata.size) { + goodix_data_statistics( + ts_test->self_noisedata.data, + ts_test->self_noisedata.size, + statistics_data, STATISTICS_DATA_LEN); + goodix_strncat(ts_test->test_info, + statistics_data, TS_RAWDATA_RESULT_MAX); + } else { + ts_err("NO valiable self_noisedata"); + goodix_strncat(ts_test->test_info, "[0,0,0]", + TS_RAWDATA_RESULT_MAX); + } + } - if (!cd || !info) { - ts_err("core_data or info is NULL"); - return -ENODEV; - } + goodix_strncat( + ts_test->test_info, "-GT", TS_RAWDATA_RESULT_MAX); + goodix_strncat(ts_test->test_info, ts->fw_version.patch_pid, + TS_RAWDATA_RESULT_MAX); + goodix_strncat(ts_test->test_info, "\n", TS_RAWDATA_RESULT_MAX); + strncpy(info->result, ts_test->test_info, + TS_RAWDATA_RESULT_MAX - 1); - ts_test = kzalloc(sizeof(*ts_test), GFP_KERNEL); - if (!ts_test) { - ts_err("Failed to alloc mem"); - return -ENOMEM; +#ifdef SAVE_IN_CSV + /* save result to file */ + goodix_save_result_data(ts_test); +#endif } - ts_test->ts = cd; - ret = goodix_tptest_prepare(ts_test); - if (ret < 0) { - ts_err("Failed to prepare TP test, exit"); - strncpy(info->result, "[FAIL]-0F-software reason\n", - TS_RAWDATA_RESULT_MAX - 1); - goto exit_finish; - } - ts_info("TP test prepare OK"); + int goodix_do_inspect( + struct goodix_ts_core * cd, struct ts_rawdata_info * info) + { + int ret; + struct goodix_ts_test *ts_test = NULL; - goodix_capacitance_test(ts_test); /* 1F 3F 6F 7F test */ - if (ts_test->test_params.test_items[GTP_SHORT_TEST]) - goodix_shortcircut_test(ts_test); /* 5F test */ - goodix_put_test_result(ts_test, info); - goodix_tptest_finish(ts_test); + if (!cd || !info) { + ts_err("core_data or info is NULL"); + return -ENODEV; + } -exit_finish: - kfree(ts_test); - return ret; -} + ts_test = kzalloc(sizeof(*ts_test), GFP_KERNEL); + if (!ts_test) + return -ENOMEM; -/* show rawdata */ -static ssize_t goodix_ts_get_rawdata_show( - struct device *dev, struct device_attribute *attr, char *buf) -{ - int ret = 0; - struct ts_rawdata_info *info = NULL; - struct goodix_ts_core *cd = dev_get_drvdata(dev); + ts_test->ts = cd; + ret = goodix_tptest_prepare(ts_test); + if (ret < 0) { + ts_err("Failed to prepare TP test, exit"); + strncpy(info->result, "[FAIL]-0F-software reason\n", + TS_RAWDATA_RESULT_MAX - 1); + goto exit_finish; + } + ts_info("TP test prepare OK"); - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - ts_err("Failed to alloc rawdata info memory"); - return -ENOMEM; + goodix_capacitance_test(ts_test); /* 1F 3F 6F 7F test */ + if (ts_test->test_params.test_items[GTP_SHORT_TEST]) + goodix_shortcircut_test(ts_test); /* 5F test */ + goodix_put_test_result(ts_test, info); + goodix_tptest_finish(ts_test); + + exit_finish: + kfree(ts_test); + return ret; } - goodix_do_inspect(cd, info); + /* show rawdata */ + static ssize_t get_rawdata_show( + struct device * dev, struct device_attribute * attr, char *buf) + { + int ret = 0; + struct ts_rawdata_info *info = NULL; + struct goodix_ts_core *cd = dev_get_drvdata(dev); - ret = snprintf(buf, PAGE_SIZE, "resultInfo: %s", info->result); + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - kfree(info); - return ret; -} + goodix_do_inspect(cd, info); -static DEVICE_ATTR(get_rawdata, S_IRUGO, goodix_ts_get_rawdata_show, NULL); - -int inspect_module_init(void) -{ - int ret; - struct kobject *def_kobj = goodix_get_default_kobj(); + ret = snprintf(buf, PAGE_SIZE, "resultInfo: %s", info->result); - /* create sysfs */ - ret = sysfs_create_file(def_kobj, &dev_attr_get_rawdata.attr); - if (ret < 0) { - ts_err("create sysfs of get_rawdata failed"); - goto err_out; + kfree(info); + return ret; } - module_initialized = true; - ts_info("inspect module init success"); - return 0; + static DEVICE_ATTR(get_rawdata, 0444, get_rawdata_show, NULL); -err_out: - ts_err("inspect module init failed!"); - return ret; -} + int inspect_module_init(void) + { + int ret; + struct kobject *def_kobj = goodix_get_default_kobj(); -void inspect_module_exit(void) -{ - struct kobject *def_kobj = goodix_get_default_kobj(); + /* create sysfs */ + ret = sysfs_create_file(def_kobj, &dev_attr_get_rawdata.attr); + if (ret < 0) { + ts_err("create sysfs of get_rawdata failed"); + goto err_out; + } - ts_info("inspect module exit"); - if (!module_initialized) - return; + module_initialized = true; + ts_info("inspect module init success"); + return 0; - sysfs_remove_file(def_kobj, &dev_attr_get_rawdata.attr); - module_initialized = false; -} + err_out: + ts_err("inspect module init failed!"); + return ret; + } + + void inspect_module_exit(void) + { + struct kobject *def_kobj = goodix_get_default_kobj(); + + ts_info("inspect module exit"); + if (!module_initialized) + return; + + sysfs_remove_file(def_kobj, &dev_attr_get_rawdata.attr); + module_initialized = false; + } diff --git a/goodix_ts_proc.c b/goodix_ts_proc.c new file mode 100644 index 0000000..37457f2 --- /dev/null +++ b/goodix_ts_proc.c @@ -0,0 +1,376 @@ +#include "goodix_ts_core.h" +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> +#include <linux/version.h> + +#define CMD_FW_UPDATE "fw_update" +#define CMD_AUTO_TEST "auto_test" +#define CMD_GET_VERSION "get_version" +#define CMD_GET_RAWDATA "get_raw" +#define CMD_GET_DIFFDATA "get_diff" +#define CMD_GET_SELF_RAWDATA "get_self_raw" +#define CMD_GET_SELF_DIFFDATA "get_self_diff" +#define CMD_SET_DOUBLE_TAP "set_double_tap" +#define CMD_SET_SINGLE_TAP "set_single_tap" +#define CMD_SET_CHARGE_MODE "set_charge_mode" +#define CMD_SET_IRQ_ENABLE "set_irq_enable" +#define CMD_SET_ESD_ENABLE "set_esd_enable" +#define CMD_SET_DEBUG_LOG "set_debug_log" + +#define SHORT_SIZE 100 +#define LARGE_SIZE 4096 +static struct goodix_ts_core *cd; +static char wbuf[SHORT_SIZE]; +static char *rbuf; +static uint32_t index; + +static void *seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= index) + return NULL; + + return rbuf + *pos; +} + +static int seq_show(struct seq_file *s, void *v) +{ + seq_printf(s, (u8 *)v); + return 0; +} + +static void *seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + *pos += index; + return NULL; +} + +static void seq_stop(struct seq_file *s, void *v) +{ + if (s->read_pos >= index) { + // ts_info("read_pos:%d", (int)s->read_pos); + kfree(rbuf); + rbuf = NULL; + index = 0; + } +} + +static const struct seq_operations seq_ops = { + .start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show +}; + +static int driver_test_open(struct inode *inode, struct file *file) +{ + memset(wbuf, 0, sizeof(wbuf)); + + return seq_open(file, &seq_ops); +} + +static int driver_test_release(struct inode *inode, struct file *file) +{ + return seq_release(inode, file); +} + +static int get_cap_data(uint8_t *type) +{ + struct goodix_ts_cmd temp_cmd; + int tx = cd->ic_info.parm.drv_num; + int rx = cd->ic_info.parm.sen_num; + uint8_t val; + int retry = 20; + struct frame_head *frame_head; + unsigned char frame_buf[GOODIX_MAX_FRAMEDATA_LEN]; + unsigned char *cur_ptr; + unsigned int flag_addr = cd->ic_info.misc.frame_data_addr; + int i; + int ret; + + /* disable irq & close esd */ + cd->hw_ops->irq_enable(cd, false); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); + + if (strstr(type, CMD_GET_RAWDATA) || + strstr(type, CMD_GET_SELF_RAWDATA)) { + temp_cmd.data[0] = 0x81; + } else { + temp_cmd.data[0] = 0x82; + } + temp_cmd.cmd = 0x90; + temp_cmd.len = 5; + ret = cd->hw_ops->send_cmd(cd, &temp_cmd); + if (ret < 0) { + ts_err("report rawdata failed, exit!"); + goto exit; + } + + /* clean touch event flag */ + val = 0; + ret = cd->hw_ops->write(cd, flag_addr, &val, 1); + if (ret < 0) { + ts_err("clean touch event failed, exit!"); + goto exit; + } + + while (retry--) { + usleep_range(2000, 2100); + ret = cd->hw_ops->read(cd, flag_addr, &val, 1); + if (!ret && (val & 0x80)) + break; + } + if (retry < 0) { + ts_err("framedata is not ready val:0x%02x, exit!", val); + ret = -EINVAL; + goto exit; + } + + ret = cd->hw_ops->read( + cd, flag_addr, frame_buf, GOODIX_MAX_FRAMEDATA_LEN); + if (ret < 0) { + ts_err("read frame data failed"); + goto exit; + } + + if (checksum_cmp(frame_buf, cd->ic_info.misc.frame_data_head_len, + CHECKSUM_MODE_U8_LE)) { + ts_err("frame head checksum error"); + ret = -EINVAL; + goto exit; + } + + frame_head = (struct frame_head *)frame_buf; + if (checksum_cmp(frame_buf, frame_head->cur_frame_len, + CHECKSUM_MODE_U16_LE)) { + ts_err("frame body checksum error"); + ret = -EINVAL; + goto exit; + } + cur_ptr = frame_buf; + cur_ptr += cd->ic_info.misc.frame_data_head_len; + cur_ptr += cd->ic_info.misc.fw_attr_len; + cur_ptr += cd->ic_info.misc.fw_log_len; + cur_ptr += 8; + + if (strstr(type, CMD_GET_RAWDATA) || strstr(type, CMD_GET_DIFFDATA)) { + goodix_rotate_abcd2cbad(tx, rx, (s16 *)cur_ptr); + for (i = 0; i < tx * rx; i++) { + index += sprintf( + &rbuf[index], "%5d,", *((s16 *)cur_ptr + i)); + if ((i + 1) % tx == 0) + index += sprintf(&rbuf[index], "\n"); + } + } else { + cur_ptr += tx * rx * 2 + 10; + index += sprintf(&rbuf[index], "TX:"); + for (i = 0; i < tx + rx; i++) { + index += sprintf( + &rbuf[index], "%5d,", *((s16 *)cur_ptr + i)); + if ((i + 1) == tx) + index += sprintf(&rbuf[index], "\nRX:"); + } + index += sprintf(&rbuf[index], "\n"); + } + +exit: + temp_cmd.cmd = 0x90; + temp_cmd.data[0] = 0; + temp_cmd.len = 5; + cd->hw_ops->send_cmd(cd, &temp_cmd); + /* enable irq & esd */ + cd->hw_ops->irq_enable(cd, true); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + return ret; +} + +static ssize_t driver_test_write( + struct file *file, const char __user *buf, size_t count, loff_t *pos) +{ + struct goodix_fw_version fw_ver; + struct ts_rawdata_info *info = NULL; + char *p = wbuf; + int ret; + + if (count > SHORT_SIZE) { + ts_err("invalid cmd size[%ld]", count); + return count; + } + + if (copy_from_user(p, buf, count) != 0) { + ts_err("copy from user failed"); + return count; + } + + kfree(rbuf); + rbuf = NULL; + index = 0; + + if (strstr(p, CMD_FW_UPDATE)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + ret = goodix_do_fw_update( + NULL, UPDATE_MODE_BLOCK | UPDATE_MODE_FORCE | + UPDATE_MODE_SRC_REQUEST); + if (ret < 0) { + index = sprintf(rbuf, "%s: NG\n", CMD_FW_UPDATE); + } else { + index = sprintf(rbuf, "%s: OK\n", CMD_FW_UPDATE); + } + } else if (strstr(p, CMD_GET_VERSION)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + ret = cd->hw_ops->read_version(cd, &fw_ver); + if (ret < 0) { + index = sprintf(rbuf, "%s: NG\n", CMD_GET_VERSION); + } else { + index = sprintf(rbuf, "%s: %02x%02x%02x%02x\n", + CMD_GET_VERSION, fw_ver.patch_vid[0], + fw_ver.patch_vid[1], fw_ver.patch_vid[2], + fw_ver.patch_vid[3]); + } + } else if (strstr(p, CMD_GET_RAWDATA)) { + rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); + ret = get_cap_data(CMD_GET_RAWDATA); + if (ret < 0) { + index = sprintf(rbuf, "%s: NG\n", CMD_GET_RAWDATA); + } + } else if (strstr(p, CMD_GET_DIFFDATA)) { + rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); + ret = get_cap_data(CMD_GET_DIFFDATA); + if (ret < 0) { + index = sprintf(rbuf, "%s: NG\n", CMD_GET_DIFFDATA); + } + } else if (strstr(p, CMD_GET_SELF_RAWDATA)) { + rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); + ret = get_cap_data(CMD_GET_SELF_RAWDATA); + if (ret < 0) { + index = sprintf(rbuf, "%s: NG\n", CMD_GET_SELF_RAWDATA); + } + } else if (strstr(p, CMD_GET_SELF_DIFFDATA)) { + rbuf = kzalloc(LARGE_SIZE, GFP_KERNEL); + ret = get_cap_data(CMD_GET_SELF_DIFFDATA); + if (ret < 0) { + index = sprintf( + rbuf, "%s: NG\n", CMD_GET_SELF_DIFFDATA); + } + } else if (strstr(p, CMD_SET_DOUBLE_TAP)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + if (strlen(p) - strlen(CMD_SET_DOUBLE_TAP) > 1) { + if (p[strlen(CMD_SET_DOUBLE_TAP) + 1] == '0') { + cd->gesture_type &= ~GESTURE_DOUBLE_TAP; + index = sprintf(rbuf, "%s: disable OK\n", + CMD_SET_DOUBLE_TAP); + } else { + cd->gesture_type |= GESTURE_DOUBLE_TAP; + index = sprintf(rbuf, "%s: enable OK\n", + CMD_SET_DOUBLE_TAP); + } + } else { + index = sprintf(rbuf, "%s: NG\n", CMD_SET_DOUBLE_TAP); + } + } else if (strstr(p, CMD_SET_SINGLE_TAP)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + if (strlen(p) - strlen(CMD_SET_SINGLE_TAP) > 1) { + if (p[strlen(CMD_SET_SINGLE_TAP) + 1] == '0') { + cd->gesture_type &= ~GESTURE_SINGLE_TAP; + index = sprintf(rbuf, "%s: disable OK\n", + CMD_SET_SINGLE_TAP); + } else { + cd->gesture_type |= GESTURE_SINGLE_TAP; + index = sprintf(rbuf, "%s: enable OK\n", + CMD_SET_SINGLE_TAP); + } + } else { + index = sprintf(rbuf, "%s: NG\n", CMD_SET_SINGLE_TAP); + } + } else if (strstr(p, CMD_SET_IRQ_ENABLE)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + if (strlen(p) - strlen(CMD_SET_IRQ_ENABLE) > 1) { + if (p[strlen(CMD_SET_IRQ_ENABLE) + 1] == '0') { + cd->hw_ops->irq_enable(cd, false); + index = sprintf(rbuf, "%s: disable OK\n", + CMD_SET_IRQ_ENABLE); + } else { + cd->hw_ops->irq_enable(cd, true); + index = sprintf(rbuf, "%s: enable OK\n", + CMD_SET_IRQ_ENABLE); + } + } else { + index = sprintf(rbuf, "%s: NG\n", CMD_SET_IRQ_ENABLE); + } + } else if (strstr(p, CMD_SET_ESD_ENABLE)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + if (strlen(p) - strlen(CMD_SET_ESD_ENABLE) > 1) { + if (p[strlen(CMD_SET_ESD_ENABLE) + 1] == '0') { + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); + index = sprintf(rbuf, "%s: disable OK\n", + CMD_SET_ESD_ENABLE); + } else { + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + index = sprintf(rbuf, "%s: enable OK\n", + CMD_SET_ESD_ENABLE); + } + } else { + index = sprintf(rbuf, "%s: NG\n", CMD_SET_ESD_ENABLE); + } + } else if (strstr(p, CMD_SET_DEBUG_LOG)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + if (strlen(p) - strlen(CMD_SET_DEBUG_LOG) > 1) { + if (p[strlen(CMD_SET_DEBUG_LOG) + 1] == '0') { + debug_log_flag = false; + index = sprintf(rbuf, "%s: disable OK\n", + CMD_SET_DEBUG_LOG); + } else { + debug_log_flag = true; + index = sprintf(rbuf, "%s: enable OK\n", + CMD_SET_DEBUG_LOG); + } + } else { + index = sprintf(rbuf, "%s: NG\n", CMD_SET_DEBUG_LOG); + } + } else if (strstr(p, CMD_AUTO_TEST)) { + rbuf = kzalloc(SHORT_SIZE, GFP_KERNEL); + info = vmalloc(sizeof(*info)); + goodix_do_inspect(cd, info); + index = sprintf(rbuf, "%s: %s", CMD_AUTO_TEST, info->result); + vfree(info); + } else { + ts_err("not support cmd[%s]", p); + } + + return count; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +static const struct proc_ops driver_test_ops = { + .proc_open = driver_test_open, + .proc_read = seq_read, + .proc_write = driver_test_write, + .proc_lseek = seq_lseek, + .proc_release = driver_test_release, +}; +#else +static const struct file_operations driver_test_ops = { + .open = driver_test_open, + .read = seq_read, + .write = driver_test_write, + .llseek = seq_lseek, + .release = driver_test_release, +}; +#endif + +int driver_test_proc_init(struct goodix_ts_core *core_data) +{ + struct proc_dir_entry *proc_entry; + + proc_entry = proc_create( + "goodix_ts/driver_test", 0777, NULL, &driver_test_ops); + if (!proc_entry) { + ts_err("failed to create proc entry"); + return -ENOMEM; + } + + cd = core_data; + return 0; +} + +void driver_test_proc_remove(void) +{ + remove_proc_entry("goodix_ts/driver_test", NULL); +}
\ No newline at end of file diff --git a/goodix_ts_tools.c b/goodix_ts_tools.c index 88e3917..ceae2b7 100644 --- a/goodix_ts_tools.c +++ b/goodix_ts_tools.c @@ -16,7 +16,6 @@ */ #include "goodix_ts_core.h" #include <linux/atomic.h> -#include <linux/compat.h> #include <linux/fs.h> #include <linux/ioctl.h> #include <linux/kernel.h> diff --git a/goodix_ts_utils.c b/goodix_ts_utils.c index 2dc08b5..ff6dafb 100644 --- a/goodix_ts_utils.c +++ b/goodix_ts_utils.c @@ -75,7 +75,6 @@ int checksum_cmp(const u8 *data, int size, int mode) return 1; for (i = 0; i < size - 2; i++) cal_checksum += data[i]; - r_checksum = data[size - 2] + (data[size - 1] << 8); return (cal_checksum & 0xFFFF) == r_checksum ? 0 : 1; } @@ -101,12 +100,12 @@ int is_risk_data(const u8 *data, int size) for (i = 0; i < size; i++) { if (data[i] == 0) zero_count++; - else if (data[i] == 0xff) + else if (data[i] == 0xFF) ff_count++; } if (zero_count == size || ff_count == size) { ts_info("warning data is all %s\n", - zero_count == size ? "zero" : "0xff"); + zero_count == size ? "0x00" : "0xFF"); return 1; } @@ -150,30 +149,54 @@ void goodix_rotate_abcd2cbad(int tx, int rx, s16 *data) } /* get ic type */ -int goodix_get_ic_type(struct device_node *node) +int goodix_get_ic_type( + struct device_node *node, struct goodix_bus_interface *bus_inf) { - const char *name_tmp; - int ret; + const struct property *prop; + char ic_name[128] = { 0 }; + int i; - ret = of_property_read_string(node, "compatible", &name_tmp); - if (ret < 0) { - ts_err("get compatible failed"); - return ret; + prop = of_find_property(node, "compatible", NULL); + if (!prop || !prop->value || prop->length > sizeof(ic_name)) { + ts_err("invalid compatible property"); + return -EINVAL; } - if (strstr(name_tmp, "9897")) { - ts_info("ic type is BerlinA"); - ret = IC_TYPE_BERLIN_A; - } else if (strstr(name_tmp, "9966") || strstr(name_tmp, "7986")) { - ts_info("ic type is BerlinB"); - ret = IC_TYPE_BERLIN_B; - } else if (strstr(name_tmp, "9916")) { - ts_info("ic type is BerlinD"); - ret = IC_TYPE_BERLIN_D; - } else { - ts_info("can't find valid ic_type"); - ret = -EINVAL; + memcpy(ic_name, prop->value, prop->length); + + /* replace string end flag with ';' */ + for (i = 0; i < prop->length - 1; i++) + if (ic_name[i] == 0) + ic_name[i] = ';'; + + ts_info("ic_name %s", ic_name); + + if (strstr(ic_name, "brl-a")) { + ts_info("ic type is brl-a"); + bus_inf->ic_type = IC_TYPE_BERLIN_A; + return 0; + } + + if (strstr(ic_name, "brl-b")) { + ts_info("ic type is brl-b"); + bus_inf->ic_type = IC_TYPE_BERLIN_B; + if (strstr(ic_name, "ga687x")) { + bus_inf->sub_ic_type = IC_TYPE_SUB_B2; + ts_info("sub ic type is brl-b2"); + } + return 0; + } + if (strstr(ic_name, "brl-d")) { + ts_info("ic type is brl-d"); + bus_inf->ic_type = IC_TYPE_BERLIN_D; + return 0; + } + if (strstr(ic_name, "nottingham")) { + ts_info("ic type is nottingham"); + bus_inf->ic_type = IC_TYPE_NOTTINGHAM; + return 0; } - return ret; + ts_err("unsupported ic type %s", ic_name); + return -EINVAL; } |