diff options
author | Jing Wang <jwangh@google.com> | 2023-04-01 03:21:20 +0000 |
---|---|---|
committer | Jing Wang <jwangh@google.com> | 2023-04-01 04:24:17 +0000 |
commit | a17332d87e6dd4f008e9575cb2f5a15fffa24fe9 (patch) | |
tree | bf1c3fe3a41c19f5b41ef9bc40ad7a363f547671 | |
parent | f7c506cc918825a37eb6a856e7dd31e7b283efdc (diff) | |
download | goodix_touch-a17332d87e6dd4f008e9575cb2f5a15fffa24fe9.tar.gz |
Revert "touch/goodix: Import driver v1.2.5"
Revert submission 2421158-ct3_touch_bringup
Reason for revert: b/276521272
Reverted changes: /q/submissionid:2421158-ct3_touch_bringup
Change-Id: Id205ec6bddab3d7b55fdfe1b56e2ba2a2bed57cb
-rw-r--r-- | goodix_brl_fwupdate.c | 466 | ||||
-rw-r--r-- | goodix_brl_hw.c | 257 | ||||
-rw-r--r-- | goodix_brl_i2c.c | 50 | ||||
-rw-r--r-- | goodix_brl_spi.c | 166 | ||||
-rw-r--r-- | goodix_cfg_bin.c | 2 | ||||
-rw-r--r-- | goodix_ts_core.c | 872 | ||||
-rw-r--r-- | goodix_ts_core.h | 292 | ||||
-rw-r--r-- | goodix_ts_gesture.c | 345 | ||||
-rw-r--r-- | goodix_ts_inspect.c | 20 | ||||
-rw-r--r-- | goodix_ts_proc.c | 333 | ||||
-rw-r--r-- | goodix_ts_tools.c | 195 | ||||
-rw-r--r-- | goodix_ts_utils.c | 15 |
12 files changed, 1920 insertions, 1093 deletions
diff --git a/goodix_brl_fwupdate.c b/goodix_brl_fwupdate.c index f7136fa..0fb81e6 100644 --- a/goodix_brl_fwupdate.c +++ b/goodix_brl_fwupdate.c @@ -137,12 +137,67 @@ struct update_info_t update_brd = { ENABLE_MISCTL_BRD, }; -enum compare_status { - COMPARE_EQUAL = 0, - COMPARE_NOCODE, - COMPARE_PIDMISMATCH, - COMPARE_FW_NOTEQUAL, - COMPARE_CFG_NOTEQUAL, +/** + * fw_subsys_info - subsytem firmware information + * @type: sybsystem type + * @size: firmware size + * @flash_addr: flash address + * @data: firmware data + */ +struct fw_subsys_info { + u8 type; + u32 size; + u32 flash_addr; + const u8 *data; +}; + +/** + * firmware_summary + * @size: fw total length + * @checksum: checksum of fw + * @hw_pid: mask pid string + * @hw_pid: mask vid code + * @fw_pid: fw pid string + * @fw_vid: fw vid code + * @subsys_num: number of fw subsystem + * @chip_type: chip type + * @protocol_ver: firmware packing + * protocol version + * @bus_type: 0 represent I2C, 1 for SPI + * @subsys: sybsystem info + */ +#pragma pack(1) +struct firmware_summary { + u32 size; + u32 checksum; + u8 hw_pid[6]; + u8 hw_vid[3]; + u8 fw_pid[FW_PID_LEN]; + u8 fw_vid[FW_VID_LEN]; + u8 subsys_num; + u8 chip_type; + u8 protocol_ver; + u8 bus_type; + u8 flash_protect; + // u8 reserved[8]; + struct fw_subsys_info subsys[FW_SUBSYS_MAX_NUM]; +}; +#pragma pack() + +/** + * firmware_data - firmware data structure + * @fw_summary: firmware information + * @firmware: firmware data structure + */ +struct firmware_data { + struct firmware_summary fw_summary; + const struct firmware *firmware; + struct firmware *fw_sysfs; +}; + +struct config_data { + u8 *data; + int size; }; #pragma pack(1) @@ -163,6 +218,90 @@ struct goodix_flash_cmd { }; #pragma pack() +enum update_status { + UPSTA_NOTWORK = 0, + UPSTA_PREPARING, + UPSTA_UPDATING, + UPSTA_SUCCESS, + UPSTA_FAILED +}; + +enum compare_status { + COMPARE_EQUAL = 0, + COMPARE_NOCODE, + COMPARE_PIDMISMATCH, + COMPARE_FW_NOTEQUAL, + COMPARE_CFG_NOTEQUAL, +}; + +/** + * fw_update_ctrl - structure used to control the + * firmware update process + * @initialized: struct init state + * @mode: indicate weather reflash config or not, fw data source, + * and run on block mode or not. + * @status: update status + * @progress: indicate the progress of update + * @fw_data: firmware data + * @fw_name: firmware name + * @attr_fwimage: sysfs bin attrs, for storing fw image + * @fw_data_src: firmware data source form sysfs, request or head file + * @kobj: pointer to the sysfs kobject + */ +struct fw_update_ctrl { + struct mutex mutex; + int initialized; + char fw_name[GOODIX_MAX_STR_LABEL_LEN]; + int mode; + enum update_status status; + int spend_time; + + struct firmware_data fw_data; + struct goodix_ic_config *ic_config; + struct goodix_ts_core *core_data; + struct update_info_t *update_info; + + struct attribute_group attrs; + struct kobject *kobj; +}; +static struct fw_update_ctrl goodix_fw_update_ctrl; +static struct goodix_ic_config one_binary_cfg; + +static int goodix_fw_update_reset(int delay) +{ + struct goodix_ts_hw_ops *hw_ops; + + hw_ops = goodix_fw_update_ctrl.core_data->hw_ops; + return hw_ops->reset(goodix_fw_update_ctrl.core_data, delay); +} + +static int get_fw_version_info(struct goodix_fw_version *fw_version) +{ + struct goodix_ts_hw_ops *hw_ops = + goodix_fw_update_ctrl.core_data->hw_ops; + + return hw_ops->read_version( + goodix_fw_update_ctrl.core_data, fw_version); +} + +static int goodix_reg_write( + unsigned int addr, unsigned char *data, unsigned int len) +{ + struct goodix_ts_hw_ops *hw_ops = + goodix_fw_update_ctrl.core_data->hw_ops; + + return hw_ops->write(goodix_fw_update_ctrl.core_data, addr, data, len); +} + +static int goodix_reg_read( + unsigned int addr, unsigned char *data, unsigned int len) +{ + struct goodix_ts_hw_ops *hw_ops = + goodix_fw_update_ctrl.core_data->hw_ops; + + return hw_ops->read(goodix_fw_update_ctrl.core_data, addr, data, len); +} + /** * goodix_parse_firmware - parse firmware header information * and subsystem information from firmware data buffer @@ -172,24 +311,26 @@ struct goodix_flash_cmd { * return: 0 - OK, < 0 - error */ /* sizeof(length) + sizeof(checksum) */ -static int goodix_parse_firmware(struct goodix_ts_core *cd, - struct firmware_data *fw_data) + +static int goodix_parse_firmware(struct firmware_data *fw_data) { const struct firmware *firmware; struct firmware_summary *fw_summary; unsigned int i, fw_offset, info_offset; u32 checksum; - int ic_type = cd->bus->ic_type; + int ic_type = goodix_fw_update_ctrl.core_data->bus->ic_type; int subsys_info_offset = - cd->update_ctrl.update_info->subsys_info_offset; - int header_size = cd->update_ctrl.update_info->header_size; - struct goodix_ic_config *one_binary_cfg = &cd->update_ctrl.one_binary_cfg; + goodix_fw_update_ctrl.update_info->subsys_info_offset; + int header_size = goodix_fw_update_ctrl.update_info->header_size; int r = 0; 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); @@ -266,10 +407,10 @@ static int goodix_parse_firmware(struct goodix_ts_core *cd, ts_debug("Subsystem Ptr:%p", fw_summary->subsys[i].data); if (fw_summary->subsys[i].type == CONFIG_DATA_TYPE) { - one_binary_cfg->len = fw_summary->subsys[i].size; - memcpy(one_binary_cfg->data, fw_summary->subsys[i].data, - one_binary_cfg->len); - cd->update_ctrl.ic_config = one_binary_cfg; + one_binary_cfg.len = fw_summary->subsys[i].size; + memcpy(one_binary_cfg.data, fw_summary->subsys[i].data, + one_binary_cfg.len); + goodix_fw_update_ctrl.ic_config = &one_binary_cfg; } } @@ -301,29 +442,33 @@ err_size: static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl) { int ret = 0; - struct goodix_ts_core *cd = fwu_ctrl->core_data; - struct goodix_fw_version *ic_ver = &cd->fw_version; - struct goodix_ic_info *ic_info = &cd->ic_info; + struct goodix_fw_version fw_version; struct firmware_summary *fw_summary = &fwu_ctrl->fw_data.fw_summary; + u32 config_id_reg = goodix_fw_update_ctrl.update_info->config_id_reg; u32 file_cfg_id; + u32 ic_cfg_id; /* compare fw_version */ - if (!memcmp(ic_ver->rom_pid, GOODIX_NOCODE, 6) || - !memcmp(ic_ver->patch_pid, GOODIX_NOCODE, 6)) { + ret = get_fw_version_info(&fw_version); + if (ret) + return -EINVAL; + + if (!memcmp(fw_version.rom_pid, GOODIX_NOCODE, 6) || + !memcmp(fw_version.patch_pid, GOODIX_NOCODE, 6)) { ts_info("there is no code in the chip"); return COMPARE_NOCODE; } - if (memcmp(ic_ver->patch_pid, fw_summary->fw_pid, FW_PID_LEN)) { - ts_err("Product ID mismatch:%s != %s", ic_ver->patch_pid, + if (memcmp(fw_version.patch_pid, fw_summary->fw_pid, FW_PID_LEN)) { + ts_err("Product ID mismatch:%s != %s", fw_version.patch_pid, fw_summary->fw_pid); return COMPARE_PIDMISMATCH; } - ret = memcmp(ic_ver->patch_vid, fw_summary->fw_vid, FW_VID_LEN); + ret = memcmp(fw_version.patch_vid, fw_summary->fw_vid, FW_VID_LEN); if (ret) { ts_info("active firmware version:%*ph", FW_VID_LEN, - ic_ver->patch_vid); + fw_version.patch_vid); ts_info("firmware file version: %*ph", FW_VID_LEN, fw_summary->fw_vid); return COMPARE_FW_NOTEQUAL; @@ -334,8 +479,10 @@ static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl) if (fwu_ctrl->ic_config && fwu_ctrl->ic_config->len > 0) { file_cfg_id = goodix_get_file_config_id(fwu_ctrl->ic_config->data); - if (ic_info->version.config_id != file_cfg_id) { - ts_info("ic_cfg_id:0x%x != file_cfg_id:0x%x", ic_info->version.config_id, + goodix_reg_read( + config_id_reg, (u8 *)&ic_cfg_id, sizeof(ic_cfg_id)); + if (ic_cfg_id != file_cfg_id) { + ts_info("ic_cfg_id:0x%x != file_cfg_id:0x%x", ic_cfg_id, file_cfg_id); return COMPARE_CFG_NOTEQUAL; } @@ -355,7 +502,7 @@ static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl) * return: 0 write success and confirm ok * < 0 failed */ -static int goodix_reg_write_confirm(struct goodix_ts_core *cd, +static int goodix_reg_write_confirm( unsigned int addr, unsigned char *data, unsigned int len) { u8 *cfm = NULL; @@ -371,11 +518,11 @@ static int goodix_reg_write_confirm(struct goodix_ts_core *cd, } for (i = 0; i < GOODIX_BUS_RETRY_TIMES; i++) { - r = cd->hw_ops->write(cd, addr, data, len); + r = goodix_reg_write(addr, data, len); if (r < 0) goto exit; - r = cd->hw_ops->read(cd, addr, cfm, len); + r = goodix_reg_read(addr, cfm, len); if (r < 0) goto exit; @@ -400,11 +547,11 @@ exit: * @fw_data: firmware data * return 0 ok, <0 error */ -static int goodix_load_isp(struct goodix_ts_core *cd, struct firmware_data *fw_data) +static int goodix_load_isp(struct firmware_data *fw_data) { struct goodix_fw_version isp_fw_version; struct fw_subsys_info *fw_isp; - u32 isp_ram_reg = cd->update_ctrl.update_info->isp_ram_reg; + u32 isp_ram_reg = goodix_fw_update_ctrl.update_info->isp_ram_reg; u8 reg_val[8] = { 0x00 }; int r; @@ -412,8 +559,8 @@ static int goodix_load_isp(struct goodix_ts_core *cd, struct firmware_data *fw_d fw_isp = &fw_data->fw_summary.subsys[0]; ts_info("Loading ISP start"); - r = goodix_reg_write_confirm(cd, isp_ram_reg, - (u8 *)fw_isp->data, fw_isp->size); + r = goodix_reg_write_confirm( + isp_ram_reg, (u8 *)fw_isp->data, fw_isp->size); if (r < 0) { ts_err("Loading ISP error"); return r; @@ -423,16 +570,17 @@ static int goodix_load_isp(struct goodix_ts_core *cd, struct firmware_data *fw_d /* SET BOOT OPTION TO 0X55 */ memset(reg_val, 0x55, 8); - r = goodix_reg_write_confirm(cd, HW_REG_CPU_RUN_FROM, reg_val, 8); + r = goodix_reg_write_confirm(HW_REG_CPU_RUN_FROM, reg_val, 8); if (r < 0) { ts_err("Failed set REG_CPU_RUN_FROM flag"); return r; } ts_info("Success write [8]0x55 to 0x%x", HW_REG_CPU_RUN_FROM); - cd->hw_ops->reset(cd, 100); + if (goodix_fw_update_reset(100)) + ts_err("reset abnormal"); /*check isp state */ - if (cd->hw_ops->read_version(cd, &isp_fw_version)) { + if (get_fw_version_info(&isp_fw_version)) { ts_err("failed read isp version"); return -2; } @@ -458,8 +606,6 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) u32 misctl_reg = fwu_ctrl->update_info->misctl_reg; u32 watch_dog_reg = fwu_ctrl->update_info->watch_dog_reg; u32 enable_misctl_val = fwu_ctrl->update_info->enable_misctl_val; - struct goodix_ts_core *cd = fwu_ctrl->core_data; - struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; u8 reg_val[4] = { 0 }; u8 temp_buf[64] = { 0 }; int retry = 20; @@ -467,17 +613,18 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) /*reset IC*/ ts_info("firmware update, reset"); - hw_ops->reset(cd, 5); + if (goodix_fw_update_reset(5)) + ts_err("reset abnormal"); retry = 100; /* Hold cpu*/ do { reg_val[0] = 0x01; reg_val[1] = 0x00; - r = hw_ops->write(cd, HOLD_CPU_REG_W, reg_val, 2); - r |= hw_ops->read(cd, HOLD_CPU_REG_R, &temp_buf[0], 4); - r |= hw_ops->read(cd, HOLD_CPU_REG_R, &temp_buf[4], 4); - r |= hw_ops->read(cd, HOLD_CPU_REG_R, &temp_buf[8], 4); + r = goodix_reg_write(HOLD_CPU_REG_W, reg_val, 2); + r |= goodix_reg_read(HOLD_CPU_REG_R, &temp_buf[0], 4); + r |= goodix_reg_read(HOLD_CPU_REG_R, &temp_buf[4], 4); + r |= goodix_reg_read(HOLD_CPU_REG_R, &temp_buf[8], 4); if (!r && !memcmp(&temp_buf[0], &temp_buf[4], 4) && !memcmp(&temp_buf[4], &temp_buf[8], 4) && !memcmp(&temp_buf[0], &temp_buf[8], 4)) { @@ -494,20 +641,20 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) ts_info("Success hold CPU"); /* enable misctl clock */ - if (cd->bus->ic_type == IC_TYPE_BERLIN_D || - cd->bus->ic_type == IC_TYPE_NOTTINGHAM) - hw_ops->write(cd, misctl_reg, (u8 *)&enable_misctl_val, 4); + 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 - hw_ops->write(cd, misctl_reg, (u8 *)&enable_misctl_val, 1); + goodix_reg_write(misctl_reg, (u8 *)&enable_misctl_val, 1); ts_info("enable misctl clock"); - if (cd->bus->ic_type == IC_TYPE_BERLIN_A) { + if (fwu_ctrl->core_data->bus->ic_type == IC_TYPE_BERLIN_A) { /* open ESD_KEY */ retry = 20; do { reg_val[0] = 0x95; - r = hw_ops->write(cd, ESD_KEY_REG, reg_val, 1); - r |= hw_ops->read(cd, ESD_KEY_REG, temp_buf, 1); + r = goodix_reg_write(ESD_KEY_REG, reg_val, 1); + r |= goodix_reg_read(ESD_KEY_REG, temp_buf, 1); if (!r && temp_buf[0] == 0x01) break; usleep_range(1000, 1100); @@ -523,11 +670,11 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) /* disable watch dog */ reg_val[0] = 0x00; - r = hw_ops->write(cd, watch_dog_reg, reg_val, 1); + r = goodix_reg_write(watch_dog_reg, reg_val, 1); ts_info("disable watch dog"); /* load ISP code and run form isp */ - r = goodix_load_isp(cd, &fwu_ctrl->fw_data); + r = goodix_load_isp(&fwu_ctrl->fw_data); if (r < 0) ts_err("Failed load and run isp"); @@ -537,18 +684,17 @@ static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) /* goodix_send_flash_cmd: send command to read or write flash data * @flash_cmd: command need to send. */ -static int goodix_send_flash_cmd(struct goodix_ts_core *cd, - struct goodix_flash_cmd *flash_cmd) +static int goodix_send_flash_cmd(struct goodix_flash_cmd *flash_cmd) { int i, ret, retry; struct goodix_flash_cmd tmp_cmd; - u32 flash_cmd_reg = cd->update_ctrl.update_info->flash_cmd_reg; + u32 flash_cmd_reg = goodix_fw_update_ctrl.update_info->flash_cmd_reg; ts_info("try send flash cmd:%*ph", (int)sizeof(flash_cmd->buf), flash_cmd->buf); memset(tmp_cmd.buf, 0, sizeof(tmp_cmd)); - ret = cd->hw_ops->write(cd, flash_cmd_reg, - flash_cmd->buf, sizeof(flash_cmd->buf)); + ret = goodix_reg_write( + flash_cmd_reg, flash_cmd->buf, sizeof(flash_cmd->buf)); if (ret) { ts_err("failed send flash cmd %d", ret); return ret; @@ -556,8 +702,8 @@ static int goodix_send_flash_cmd(struct goodix_ts_core *cd, retry = 5; for (i = 0; i < retry; i++) { - ret = cd->hw_ops->read(cd, flash_cmd_reg, - tmp_cmd.buf, sizeof(tmp_cmd.buf)); + ret = goodix_reg_read( + flash_cmd_reg, tmp_cmd.buf, sizeof(tmp_cmd.buf)); if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS) break; usleep_range(5000, 5100); @@ -575,8 +721,8 @@ static int goodix_send_flash_cmd(struct goodix_ts_core *cd, msleep(50); retry = 20; for (i = 0; i < retry; i++) { - ret = cd->hw_ops->read(cd, flash_cmd_reg, - tmp_cmd.buf, sizeof(tmp_cmd.buf)); + ret = goodix_reg_read( + flash_cmd_reg, tmp_cmd.buf, sizeof(tmp_cmd.buf)); if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS && tmp_cmd.status == FLASH_CMD_W_STATUS_WRITE_OK) { ts_info("flash status check pass"); @@ -614,17 +760,16 @@ static int goodix_send_flash_cmd(struct goodix_ts_core *cd, } } -static int goodix_flash_package(struct goodix_ts_core *cd, - u8 subsys_type, u8 *pkg, - u32 flash_addr, u16 pkg_len) +static int goodix_flash_package( + u8 subsys_type, u8 *pkg, u32 flash_addr, u16 pkg_len) { int ret, retry; struct goodix_flash_cmd flash_cmd; - u32 isp_buffer_reg = cd->update_ctrl.update_info->isp_buffer_reg; + u32 isp_buffer_reg = goodix_fw_update_ctrl.update_info->isp_buffer_reg; retry = 2; do { - ret = cd->hw_ops->write(cd, isp_buffer_reg, pkg, pkg_len); + ret = goodix_reg_write(isp_buffer_reg, pkg, pkg_len); if (ret < 0) { ts_err("Failed to write firmware packet"); return ret; @@ -641,7 +786,7 @@ static int goodix_flash_package(struct goodix_ts_core *cd, goodix_append_checksum( &(flash_cmd.buf[2]), 9, CHECKSUM_MODE_U8_LE); - ret = goodix_send_flash_cmd(cd, &flash_cmd); + ret = goodix_send_flash_cmd(&flash_cmd); if (!ret) { ts_info("success write package to 0x%05X, len %d", flash_addr, pkg_len - 4); @@ -662,8 +807,7 @@ static int goodix_flash_package(struct goodix_ts_core *cd, * @subsys: subsystem information * return: 0 ok, < 0 error */ -static int goodix_flash_subsystem(struct goodix_ts_core *cd, - struct fw_subsys_info *subsys) +static int goodix_flash_subsystem(struct fw_subsys_info *subsys) { u32 data_size, offset; u32 total_size; @@ -696,7 +840,7 @@ static int goodix_flash_subsystem(struct goodix_ts_core *cd, goodix_append_checksum( fw_packet, data_size, CHECKSUM_MODE_U16_LE); - r = goodix_flash_package(cd, subsys->type, fw_packet, + r = goodix_flash_package(subsys->type, fw_packet, subsys_base_addr + offset, data_size + 4); if (r) { ts_err("failed flash to 0x%05X,size:%u bytes", @@ -740,7 +884,7 @@ static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl) subsys_cfg.size = GOODIX_CFG_MAX_SIZE; subsys_cfg.flash_addr = config_data_reg; subsys_cfg.type = CONFIG_DATA_TYPE; - r = goodix_flash_subsystem(fw_ctrl->core_data, &subsys_cfg); + r = goodix_flash_subsystem(&subsys_cfg); if (r) { ts_err("failed flash config with ISP, %d", r); return r; @@ -751,7 +895,7 @@ static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl) for (i = 1; i < fw_num && retry;) { ts_info("--- Start to flash subsystem[%d] ---", i); fw_x = &fw_summary->subsys[i]; - r = goodix_flash_subsystem(fw_ctrl->core_data, fw_x); + r = goodix_flash_subsystem(fw_x); if (r == 0) { ts_info("--- End flash subsystem[%d]: OK ---", i); i++; @@ -778,24 +922,10 @@ exit_flash: */ static int goodix_update_finish(struct fw_update_ctrl *fwu_ctrl) { - struct goodix_ts_core *cd = fwu_ctrl->core_data; int ret; - /* step 1: reset IC */ - cd->hw_ops->reset(cd, 100); - /* step 2: read version */ - ret = cd->hw_ops->read_version(cd, &cd->fw_version); - if (ret < 0) { - ts_err("still failed to read version after upgraded"); - return -EFAULT; - } - /* step 3: read ic info */ - ret = cd->hw_ops->get_ic_info(cd, &cd->ic_info); - if (ret < 0) { - ts_err("still failed to read ic info after upgraded"); - return -EFAULT; - } - + if (goodix_fw_update_reset(100)) + ts_err("reset abnormal"); ret = goodix_fw_version_compare(fwu_ctrl); if (ret == COMPARE_EQUAL || ret == COMPARE_CFG_NOTEQUAL) return 0; @@ -816,7 +946,7 @@ int goodix_fw_update_proc(struct fw_update_ctrl *fwu_ctrl) int retry1 = FW_UPDATE_RETRY; int ret = 0; - ret = goodix_parse_firmware(fwu_ctrl->core_data, &fwu_ctrl->fw_data); + ret = goodix_parse_firmware(&fwu_ctrl->fw_data); if (ret < 0) return ret; @@ -878,10 +1008,7 @@ static ssize_t update_en_store(struct device *dev, { int ret = 0; int mode = 0; - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); - struct fw_update_ctrl *fw_ctrl = &cd->update_ctrl; + struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; if (!buf || count <= 0) { ts_err("invalid params"); @@ -908,7 +1035,7 @@ static ssize_t update_en_store(struct device *dev, return -EINVAL; } - ret = goodix_do_fw_update(cd, mode); + ret = goodix_do_fw_update(NULL, mode); if (!ret) { ts_info("success do update work"); return count; @@ -917,18 +1044,36 @@ static ssize_t update_en_store(struct device *dev, return -EINVAL; } -/* - * [GOOG] - * return fw_update result - */ +static ssize_t fwimage_write(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t pos, size_t count) +{ + struct firmware **fw = &goodix_fw_update_ctrl.fw_data.fw_sysfs; + + 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 > GOODIX_FW_MAX_SIEZE) + return -EFAULT; + memcpy((u8 *)&(*fw)->data[pos], buf, count); + (*fw)->size = pos + count; + + return count; +} + +/* return fw_update result */ static ssize_t result_show( - struct device *dev, struct device_attribute *attr, - char *buf) + struct device *dev, struct device_attribute *attr, char *buf) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); - struct fw_update_ctrl *fw_ctrl = &cd->update_ctrl; + struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; char str[GOODIX_MAX_STR_LABEL_LEN] = { 0 }; int r = -EINVAL; @@ -954,51 +1099,57 @@ static ssize_t result_show( break; } - r = snprintf(buf, PAGE_SIZE, "result:%s spend_time:%dms\n", - str, fw_ctrl->spend_time); + r = snprintf(buf, PAGE_SIZE, "result:%s spend_time:%dms\n", str, + fw_ctrl->spend_time); return r; } -/* [GOOG] */ static DEVICE_ATTR_WO(update_en); static DEVICE_ATTR_RO(result); -static struct attribute *goodix_fwu_attrs[] = { +static struct attribute *goodix_attrs[] = { &dev_attr_update_en.attr, &dev_attr_result.attr, - NULL + NULL, +}; + +static BIN_ATTR_WO(fwimage, 0); +static struct bin_attribute *goodix_bin_attrs[] = { + &bin_attr_fwimage, + NULL, }; -static int goodix_fw_sysfs_init(struct goodix_ts_core *core_data, - struct fw_update_ctrl *fw_ctrl) +static int goodix_fw_sysfs_init( + struct goodix_ts_core *core_data, struct fw_update_ctrl *fw_ctrl) { int ret = 0; - fw_ctrl->kobj = kobject_create_and_add("fwupdate", - &core_data->pdev->dev.kobj); + fw_ctrl->kobj = + kobject_create_and_add("fwupdate", &core_data->pdev->dev.kobj); if (!fw_ctrl->kobj) { ts_err("failed create sub dir for fwupdate"); return -EINVAL; } - /* [GOOG] */ - fw_ctrl->attrs.attrs = goodix_fwu_attrs; + fw_ctrl->attrs.attrs = goodix_attrs; + fw_ctrl->attrs.bin_attrs = goodix_bin_attrs; ret = sysfs_create_group(fw_ctrl->kobj, &fw_ctrl->attrs); if (ret) { ts_err("Cannot create sysfs structure!\n"); kobject_put(fw_ctrl->kobj); + return -ENODEV; } - /*~[GOOG]*/ return ret; } -static void goodix_fw_sysfs_remove(struct goodix_ts_core *cd) +static void goodix_fw_sysfs_remove(void) { - struct fw_update_ctrl *fw_ctrl = &cd->update_ctrl; + struct fw_update_ctrl *fw_ctrl = &goodix_fw_update_ctrl; - sysfs_remove_group(fw_ctrl->kobj, &fw_ctrl->attrs); /* [GOOG] */ + sysfs_remove_group(fw_ctrl->kobj, &fw_ctrl->attrs); + kobject_put(fw_ctrl->kobj); } /** @@ -1050,7 +1201,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 goodix_ts_core *cd = fwu_ctrl->core_data; ktime_t start, end; int r = -EINVAL; @@ -1060,10 +1210,7 @@ static int goodix_fw_update_thread(void *data) mutex_lock(&fwu_ctrl->mutex); ts_debug("notify update start"); - if (cd->init_stage >= CORE_INIT_STAGE2) { - cd->hw_ops->irq_enable(cd, 0); - goodix_ts_esd_off(cd); - } + goodix_ts_blocking_notify(NOTIFY_FWUPDATE_START, NULL); if (fwu_ctrl->mode & UPDATE_MODE_SRC_REQUEST) { ts_info("Firmware request update starts"); @@ -1071,6 +1218,21 @@ static int goodix_fw_update_thread(void *data) &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.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; @@ -1082,8 +1244,13 @@ static int goodix_fw_update_thread(void *data) r = goodix_fw_update_proc(fwu_ctrl); /* clean */ - if (fwu_ctrl->mode & UPDATE_MODE_SRC_REQUEST) + 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); + } out: fwu_ctrl->mode = UPDATE_MODE_DEFAULT; mutex_unlock(&fwu_ctrl->mutex); @@ -1091,25 +1258,23 @@ out: if (r) { ts_err("fw update failed, %d", r); fwu_ctrl->status = UPSTA_FAILED; + goodix_ts_blocking_notify(NOTIFY_FWUPDATE_FAILED, NULL); } else { ts_info("fw update success"); fwu_ctrl->status = UPSTA_SUCCESS; + goodix_ts_blocking_notify(NOTIFY_FWUPDATE_SUCCESS, NULL); } end = ktime_get(); fwu_ctrl->spend_time = ktime_to_ms(ktime_sub(end, start)); - if (cd->init_stage >= CORE_INIT_STAGE2) { - cd->hw_ops->irq_enable(cd, 1); - goodix_ts_esd_on(cd); - } return r; } -int goodix_do_fw_update(struct goodix_ts_core *cd, int mode) +int goodix_do_fw_update(struct goodix_ic_config *ic_config, int mode) { struct task_struct *fwu_thrd; - struct fw_update_ctrl *fwu_ctrl = &cd->update_ctrl; + struct fw_update_ctrl *fwu_ctrl = &goodix_fw_update_ctrl; int ret; if (!fwu_ctrl->initialized) { @@ -1118,7 +1283,7 @@ int goodix_do_fw_update(struct goodix_ts_core *cd, int mode) } fwu_ctrl->mode = mode; - fwu_ctrl->ic_config = cd->ic_configs[CONFIG_TYPE_NORMAL]; + fwu_ctrl->ic_config = ic_config; ts_debug("fw update mode 0x%x", mode); if (fwu_ctrl->mode & UPDATE_MODE_BLOCK) { ret = goodix_fw_update_thread(fwu_ctrl); @@ -1144,34 +1309,37 @@ int goodix_fw_update_init(struct goodix_ts_core *core_data) return -ENODEV; } - mutex_init(&core_data->update_ctrl.mutex); - core_data->update_ctrl.core_data = core_data; - core_data->update_ctrl.mode = 0; + mutex_init(&goodix_fw_update_ctrl.mutex); + goodix_fw_update_ctrl.core_data = core_data; + goodix_fw_update_ctrl.mode = 0; - strlcpy(core_data->update_ctrl.fw_name, core_data->board_data.fw_name, - sizeof(core_data->update_ctrl.fw_name)); + strlcpy(goodix_fw_update_ctrl.fw_name, core_data->board_data.fw_name, + sizeof(goodix_fw_update_ctrl.fw_name)); - ret = goodix_fw_sysfs_init(core_data, &core_data->update_ctrl); + ret = goodix_fw_sysfs_init(core_data, &goodix_fw_update_ctrl); if (ret) { ts_err("failed create fwupate sysfs node"); return ret; } if (core_data->bus->ic_type == IC_TYPE_BERLIN_A) - core_data->update_ctrl.update_info = &update_bra; + goodix_fw_update_ctrl.update_info = &update_bra; else if (core_data->bus->ic_type == IC_TYPE_BERLIN_B) - core_data->update_ctrl.update_info = &update_brb; + goodix_fw_update_ctrl.update_info = &update_brb; else - core_data->update_ctrl.update_info = &update_brd; + goodix_fw_update_ctrl.update_info = &update_brd; - core_data->update_ctrl.initialized = 1; + goodix_fw_update_ctrl.initialized = 1; return 0; } -void goodix_fw_update_uninit(struct goodix_ts_core *core_data) +void goodix_fw_update_uninit(void) { - if (!core_data->update_ctrl.initialized) + if (!goodix_fw_update_ctrl.initialized) return; - goodix_fw_sysfs_remove(core_data); - core_data->update_ctrl.initialized = 0; - mutex_destroy(&core_data->update_ctrl.mutex); + + mutex_lock(&goodix_fw_update_ctrl.mutex); + goodix_fw_sysfs_remove(); + goodix_fw_update_ctrl.initialized = 0; + mutex_unlock(&goodix_fw_update_ctrl.mutex); + mutex_destroy(&goodix_fw_update_ctrl.mutex); } diff --git a/goodix_brl_hw.c b/goodix_brl_hw.c index cb073e1..acfd294 100644 --- a/goodix_brl_hw.c +++ b/goodix_brl_hw.c @@ -79,10 +79,6 @@ static int brl_dev_confirm(struct goodix_ts_core *cd) u8 tx_buf[8] = { 0 }; u8 rx_buf[8] = { 0 }; - if (cd->bus->ic_type == IC_TYPE_BERLIN_A && - cd->bus->bus_type == GOODIX_BUS_TYPE_SPI) - return brl_select_spi_mode(cd); - memset(tx_buf, DEV_CONFIRM_VAL, sizeof(tx_buf)); while (retry--) { ret = hw_ops->write( @@ -118,6 +114,11 @@ static int brl_reset_after(struct goodix_ts_core *cd) ts_info("IN"); + /* select spi mode */ + ret = brl_select_spi_mode(cd); + if (ret < 0) + return ret; + /* hold cpu */ retry = GOODIX_RETRY_10; while (retry--) { @@ -849,7 +850,7 @@ static int convert_ic_info(struct goodix_ic_info *info, const u8 *data) return 0; } -void print_ic_info(struct goodix_ic_info *ic_info) +static void print_ic_info(struct goodix_ic_info *ic_info) { struct goodix_ic_info_version *version = &ic_info->version; struct goodix_ic_info_feature *feature = &ic_info->feature; @@ -974,6 +975,8 @@ static int brl_get_ic_info( return ret; } + print_ic_info(ic_info); + /* check some key info */ if (!ic_info->misc.cmd_addr || !ic_info->misc.fw_buffer_addr || !ic_info->misc.touch_data_addr) { @@ -1016,7 +1019,6 @@ static int brl_esd_check(struct goodix_ts_core *cd) #define IRQ_EVENT_HEAD_LEN 8 #define BYTES_PER_POINT 14 -#define BYTES_STYLUS_LEN 16 #define COOR_DATA_CHECKSUM_SIZE 2 #define GOODIX_TOUCH_EVENT 0x80 @@ -1026,42 +1028,69 @@ static int brl_esd_check(struct goodix_ts_core *cd) #define GOODIX_FP_EVENT 0x08 #define POINT_TYPE_STYLUS_HOVER 0x01 #define POINT_TYPE_STYLUS 0x03 -static void goodix_parse_finger(struct goodix_ts_core *cd, - struct goodix_touch_data *touch_data, - u8 *buf, int id) +static int point_struct_len; +static void goodix_parse_finger( + struct goodix_touch_data *touch_data, u8 *buf, int touch_num) { - int point_struct_len = cd->ic_info.misc.point_struct_len; - struct goodix_ts_coords *coord = &touch_data->coords[id]; /* [GOOG] */ - - coord->status = TS_TOUCH; - coord->x = le16_to_cpup((__le16 *)(buf + 2)); - coord->y = le16_to_cpup((__le16 *)(buf + 4)); - coord->w = le16_to_cpup((__le16 *)(buf + 6)); - if (point_struct_len > 8) { - coord->p = buf[8]; - coord->major = le16_to_cpup((__le16 *)(buf + 9)); - coord->minor = le16_to_cpup((__le16 *)(buf + 11)); - coord->angle = (signed char)buf[13]; - } - touch_data->touch_num += 1; + unsigned int id = 0; + u8 *coor_data; + int i; + struct goodix_ts_coords *coord; + + coor_data = &buf[IRQ_EVENT_HEAD_LEN]; + for (i = 0; i < touch_num; i++) { + id = (coor_data[0] >> 4) & 0x0F; + if (id >= GOODIX_MAX_TOUCH) { + ts_info("invalid finger id =%d", id); + touch_data->touch_num = 0; + return; + } + coord = &touch_data->coords[id]; + + coord->status = TS_TOUCH; + coord->x = le16_to_cpup((__le16 *)(coor_data + 2)); + coord->y = le16_to_cpup((__le16 *)(coor_data + 4)); + coord->w = le16_to_cpup((__le16 *)(coor_data + 6)); + + if (point_struct_len > 8) { + coord->p = coor_data[8]; + coord->major = le16_to_cpup((__le16 *)(coor_data + 9)); + coord->minor = le16_to_cpup((__le16 *)(coor_data + 11)); + coord->angle = (signed char)coor_data[13]; + } + + coor_data += point_struct_len; + } + touch_data->touch_num = touch_num; } static unsigned int goodix_pen_btn_code[] = { BTN_STYLUS, BTN_STYLUS2 }; static void goodix_parse_pen( - struct goodix_pen_data *pen_data, u8 *event_head, u8 *buf) + struct goodix_pen_data *pen_data, u8 *buf, int touch_num) { + unsigned int id = 0; u8 cur_key_map = 0; + u8 *coor_data; int16_t x_angle, y_angle; int i; - pen_data->coords.status = TS_TOUCH; - pen_data->coords.x = le16_to_cpup((__le16 *)(buf + 2)); - pen_data->coords.y = le16_to_cpup((__le16 *)(buf + 4)); - pen_data->coords.p = le16_to_cpup((__le16 *)(buf + 6)); - x_angle = le16_to_cpup((__le16 *)(buf + 8)); - y_angle = le16_to_cpup((__le16 *)(buf + 10)); - pen_data->coords.tilt_x = x_angle / 100; - pen_data->coords.tilt_y = y_angle / 100; + pen_data->coords.tool_type = BTN_TOOL_PEN; + + if (touch_num) { + pen_data->coords.status = TS_TOUCH; + coor_data = &buf[IRQ_EVENT_HEAD_LEN]; + + id = (coor_data[0] >> 4) & 0x0F; + pen_data->coords.x = le16_to_cpup((__le16 *)(coor_data + 2)); + pen_data->coords.y = le16_to_cpup((__le16 *)(coor_data + 4)); + pen_data->coords.p = le16_to_cpup((__le16 *)(coor_data + 6)); + x_angle = le16_to_cpup((__le16 *)(coor_data + 8)); + y_angle = le16_to_cpup((__le16 *)(coor_data + 10)); + pen_data->coords.tilt_x = x_angle / 100; + pen_data->coords.tilt_y = y_angle / 100; + } else { + pen_data->coords.status = TS_RELEASE; + } cur_key_map = (buf[3] & 0x0F) >> 1; for (i = 0; i < GOODIX_MAX_PEN_KEY; i++) { @@ -1072,7 +1101,7 @@ static void goodix_parse_pen( } } -static int goodix_update_heatmap(struct goodix_ts_core *cd, u8 *event_data) +static int goodix_update_heatmap(struct goodix_ts_core *cd, uint8_t *event_data) { struct goodix_ic_info_misc *misc = &cd->ic_info.misc; int tx = cd->ic_info.parm.drv_num; @@ -1101,90 +1130,113 @@ static int goodix_touch_handler(struct goodix_ts_core *cd, struct goodix_ic_info_misc *misc = &cd->ic_info.misc; struct goodix_touch_data *touch_data = &ts_event->touch_data; struct goodix_pen_data *pen_data = &ts_event->pen_data; - u8 *data = event_data->data; - u8 touch_num; - int checksum_len = 0; int ret = 0; - u8 point_type; - int tid; - int i; + u8 point_type = 0; + static u8 pre_finger_num; + static u8 pre_pen_num; - touch_data->touch_num = 0; /* [GOOG] */ - touch_num = event_data->touches; - if (touch_num > 0) { - /* - * [GOOG] - * Touch Packet: 8 bytes header + data(stylus or finger). - */ - for (i = 0; i < touch_num; i++) { - point_type = event_data->type; - tid = (data[0] >> 4) & 0x0F; - if (point_type == POINT_TYPE_STYLUS || - point_type == POINT_TYPE_STYLUS_HOVER) { - goodix_parse_pen(pen_data, (u8 *)event_data, data); - checksum_len += BYTES_STYLUS_LEN; - data += BYTES_STYLUS_LEN; - } else { - /* [GOOG] */ - if (tid >= GOODIX_MAX_TOUCH) - ts_info("invalid touch#%d id %d", i, tid); - else - goodix_parse_finger(cd, touch_data, data, tid); - checksum_len += misc->point_struct_len; - data += misc->point_struct_len; + if (event_data->touches > GOODIX_MAX_TOUCH) { + ts_debug("invalid touch num %d", event_data->touches); + return -EINVAL; + } + + if (event_data->touches > 0) { + point_type = event_data->data[0] & 0x0F; + if (point_type == POINT_TYPE_STYLUS || + point_type == POINT_TYPE_STYLUS_HOVER) { + ret = checksum_cmp(event_data->data, 16 + 2, CHECKSUM_MODE_U8_LE); + if (ret) { + ts_debug("touch data checksum error"); + ts_debug("data:%*ph", 16 + 2, event_data->data); + return -EINVAL; + } + } else { + point_struct_len = misc->point_struct_len; + ret = checksum_cmp(event_data->data, + event_data->touches * point_struct_len + 2, + CHECKSUM_MODE_U8_LE); + if (ret) { + ts_debug("touch data checksum error"); + ts_debug("data:%*ph", + event_data->touches * point_struct_len + + 2, + event_data->data); + return -EINVAL; } - } - ret = checksum_cmp(event_data->data, - checksum_len + 2, - CHECKSUM_MODE_U8_LE); - if (ret) { - ts_debug("touch data checksum error"); - return -EINVAL; } } - goodix_update_heatmap(cd, event_data->data); /* [GOOG] */ + goodix_update_heatmap(cd, (u8 *)event_data); ts_event->fp_flag = event_data->fp_flag; - ts_event->event_type |= EVENT_TOUCH; - if (cd->board_data.pen_enable) - ts_event->event_type |= EVENT_PEN; + + if (event_data->touches > 0 && + (point_type == POINT_TYPE_STYLUS || + point_type == POINT_TYPE_STYLUS_HOVER)) { + /* stylus info */ + if (pre_finger_num) { + ts_event->event_type = EVENT_TOUCH; + goodix_parse_finger(touch_data, (u8 *)event_data, 0); + pre_finger_num = 0; + } else { + pre_pen_num = 1; + ts_event->event_type = EVENT_PEN; + goodix_parse_pen(pen_data, (u8 *)event_data, + event_data->touches); + } + } else { + /* finger info */ + if (pre_pen_num) { + ts_event->event_type = EVENT_PEN; + goodix_parse_pen(pen_data, (u8 *)event_data, 0); + pre_pen_num = 0; + } else { + ts_event->event_type = EVENT_TOUCH; + goodix_parse_finger(touch_data, (u8 *)event_data, + event_data->touches); + pre_finger_num = event_data->touches; + } + } + + if (event_data->status_changed) + ts_event->event_type |= EVENT_STATUS; + + /* process custom info */ + if (event_data->custom_coor_info_flag) + ts_debug("TODO add custom info process function"); return 0; } -static int brl_event_handler(struct goodix_ts_core *cd, - struct goodix_ts_event *ts_event) +static int brl_event_handler( + struct goodix_ts_core *cd, struct goodix_ts_event *ts_event) { struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; struct goodix_ic_info_misc *misc = &cd->ic_info.misc; -/* [GOOG] */ struct goodix_ts_event_data *event_data; int ret; - if (!cd->touch_frame_package || !cd->touch_frame_size) - return -ENOMEM; - ret = hw_ops->read_fast(cd, misc->touch_data_addr, - cd->touch_frame_package, cd->touch_frame_size); + cd->touch_frame_package, cd->touch_frame_size); if (ret) { ts_debug("failed get event head data"); return ret; } - event_data = (struct goodix_ts_event_data *)cd->touch_frame_package->data; + event_data = + (struct goodix_ts_event_data *)cd->touch_frame_package->data; if (event_data->type == 0x00) { ts_debug("invalid touch head"); return -EINVAL; } if (checksum_cmp((u8 *)event_data, IRQ_EVENT_HEAD_LEN, - CHECKSUM_MODE_U8_LE)) { + CHECKSUM_MODE_U8_LE)) { ts_debug("touch head checksum err[%*ph]", IRQ_EVENT_HEAD_LEN, event_data); + hw_ops->after_event_handler(cd); return -EINVAL; } -/*~[GOOG]*/ /* clean event buffer */ memset(ts_event, 0, sizeof(*ts_event)); @@ -1193,32 +1245,9 @@ static int brl_event_handler(struct goodix_ts_core *cd, ts_event->clear_count1 = event_data->clear_count1; ts_event->clear_count2 = event_data->clear_count2; /* read status event */ - if (event_data->status_changed) { - ts_event->event_type |= EVENT_STATUS; + if (event_data->status_changed) hw_ops->read(cd, 0x1021C, (u8 *)&ts_event->status_data, sizeof(ts_event->status_data)); - } - -/* - * [GOOG] - * Use goodix_update_heatmap() to do the heatmap process and - * move after_event_handler() into goodix_ts_core.c. - * - // read done - hw_ops->after_event_handler(cd); - - if (cd->heatmap_buffer) { - offset = 248 + misc->frame_data_head_len + - misc->fw_attr_len + misc->fw_log_len + 8; - memcpy(cd->heatmap_diff, &pre_buf[offset], tx * rx * 2); - goodix_rotate_abcd2cbad(tx, rx, cd->heatmap_diff); - offset = 248 + misc->frame_data_head_len + - misc->fw_attr_len + misc->fw_log_len + - misc->mutual_struct_len + 10; - memcpy(cd->heatmap_selfdiff, &pre_buf[offset], (tx + rx) * 2); - } - *~[GOOG] - */ if (event_data->type & (GOODIX_TOUCH_EVENT >> 4)) return goodix_touch_handler(cd, ts_event, @@ -1227,7 +1256,7 @@ static int brl_event_handler(struct goodix_ts_core *cd, if (event_data->type & (GOODIX_REQUEST_EVENT >> 4)) { struct goodix_ts_request_event_data *request = (struct goodix_ts_request_event_data *)event_data; - ts_event->event_type |= EVENT_REQUEST; + ts_event->event_type = EVENT_REQUEST; if (request->request_type == BRL_REQUEST_CODE_CONFIG) ts_event->request_code = REQUEST_TYPE_CONFIG; else if (request->request_type == BRL_REQUEST_CODE_RESET) @@ -1263,7 +1292,9 @@ static int brl_event_handler(struct goodix_ts_core *cd, if (event_data->type & (GOODIX_GESTURE_EVENT >> 4)) { struct goodix_ts_gesture_event_data *gesture = (struct goodix_ts_gesture_event_data *)event_data; - ts_event->event_type |= EVENT_GESTURE; + ts_event->event_type = EVENT_GESTURE; + if (event_data->status_changed) + ts_event->event_type |= EVENT_STATUS; ts_event->gesture_data.gesture_type = gesture->gesture_type; ts_event->gesture_data.touches = gesture->touches; memcpy(ts_event->gesture_data.data, gesture->data, @@ -1363,7 +1394,7 @@ static int brld_get_cap_data( /* disable irq & close esd */ brl_irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); info->buff[0] = rx; info->buff[1] = tx; @@ -1410,7 +1441,7 @@ exit: brl_send_cmd(cd, &temp_cmd); /* enable irq & esd */ brl_irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); return ret; } @@ -1441,7 +1472,7 @@ static int brl_get_capacitance_data( /* disable irq & close esd */ brl_irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); /* switch rawdata mode */ temp_cmd.cmd = GOODIX_CMD_RAWDATA; @@ -1504,7 +1535,7 @@ exit: brl_write(cd, flag_addr, &val, 1); /* enable irq & esd */ brl_irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); return ret; } diff --git a/goodix_brl_i2c.c b/goodix_brl_i2c.c index b1409f2..60018a6 100644 --- a/goodix_brl_i2c.c +++ b/goodix_brl_i2c.c @@ -25,6 +25,8 @@ #define GOODIX_BUS_RETRY_TIMES 2 #define GOODIX_REG_ADDR_SIZE 4 +static struct platform_device *goodix_pdev; +struct goodix_bus_interface goodix_i2c_bus; static int goodix_i2c_read(struct device *dev, unsigned int reg, unsigned char *data, unsigned int len) @@ -154,10 +156,15 @@ write_exit: return r; } +static void goodix_pdev_release(struct device *dev) +{ + ts_info("goodix pdev released"); + kfree(goodix_pdev); +} + static int goodix_i2c_probe( struct i2c_client *client, const struct i2c_device_id *dev_id) { - struct goodix_device_resource *dev_res; int ret = 0; ts_info("goodix i2c probe in"); @@ -165,45 +172,52 @@ static int goodix_i2c_probe( if (!ret) return -EIO; - dev_res = kzalloc(sizeof(*dev_res), GFP_KERNEL); - if (!dev_res) - return -ENOMEM; - goodix_device_register(dev_res); - /* get ic type */ - ret = goodix_get_ic_type(client->dev.of_node, &dev_res->bus); + ret = goodix_get_ic_type(client->dev.of_node, &goodix_i2c_bus); if (ret < 0) return ret; - dev_res->bus.bus_type = GOODIX_BUS_TYPE_I2C; - dev_res->bus.dev = &client->dev; - dev_res->bus.read = goodix_i2c_read; - dev_res->bus.write = goodix_i2c_write; + goodix_i2c_bus.bus_type = GOODIX_BUS_TYPE_I2C; + goodix_i2c_bus.dev = &client->dev; + goodix_i2c_bus.read = goodix_i2c_read; + goodix_i2c_bus.write = goodix_i2c_write; + /* ts core device */ + goodix_pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!goodix_pdev) + return -ENOMEM; - dev_res->pdev.name = GOODIX_CORE_DRIVER_NAME; - dev_res->pdev.id = dev_res->id; - dev_res->pdev.num_resources = 0; + goodix_pdev->name = GOODIX_CORE_DRIVER_NAME; + goodix_pdev->id = 0; + goodix_pdev->num_resources = 0; + /* + * you can find this platform dev in + * /sys/devices/platform/goodix_ts.0 + * goodix_pdev->dev.parent = &client->dev; + */ + goodix_pdev->dev.platform_data = &goodix_i2c_bus; + goodix_pdev->dev.release = goodix_pdev_release; /* register platform device, then the goodix_ts_core * module will probe the touch device. */ - ret = platform_device_register(&dev_res->pdev); + ret = platform_device_register(goodix_pdev); if (ret) { ts_err("failed register goodix platform device, %d", ret); goto err_pdev; } ts_info("i2c probe out"); - return 0; + return ret; err_pdev: - kfree(dev_res); + kfree(goodix_pdev); + goodix_pdev = NULL; ts_info("i2c probe out, %d", ret); return ret; } static int goodix_i2c_remove(struct i2c_client *client) { - // platform_device_unregister(goodix_pdev); + platform_device_unregister(goodix_pdev); return 0; } diff --git a/goodix_brl_spi.c b/goodix_brl_spi.c index e3421b9..b7d82da 100644 --- a/goodix_brl_spi.c +++ b/goodix_brl_spi.c @@ -36,6 +36,9 @@ #define SPI_WRITE_FLAG 0xF0 #define SPI_READ_FLAG 0xF1 +static struct platform_device *goodix_pdev; +struct goodix_bus_interface goodix_spi_bus; + /** * goodix_spi_read_bra- read device register through spi bus * @dev: pointer to device data @@ -48,8 +51,6 @@ static int goodix_spi_read_bra(struct device *dev, unsigned int addr, unsigned char *data, unsigned int len) { struct spi_device *spi = to_spi_device(dev); - struct goodix_ts_core *cd = dev_get_drvdata(dev); - struct goodix_bus_interface *bus = cd->bus; u8 *rx_buf = NULL; u8 *tx_buf = NULL; struct spi_transfer xfers; @@ -57,12 +58,12 @@ static int goodix_spi_read_bra(struct device *dev, unsigned int addr, int ret = 0; int buf_len = SPI_READ_PREFIX_LEN + len; - mutex_lock(&bus->mutex); + mutex_lock(&goodix_spi_bus.mutex); if (buf_len <= SPI_PREALLOC_RX_BUF_SIZE && buf_len <= SPI_PREALLOC_TX_BUF_SIZE) { - rx_buf = bus->rx_buf; - tx_buf = bus->tx_buf; + rx_buf = goodix_spi_bus.rx_buf; + tx_buf = goodix_spi_bus.tx_buf; memset(tx_buf, 0, buf_len); } else { rx_buf = kzalloc(buf_len, GFP_KERNEL); @@ -107,13 +108,13 @@ static int goodix_spi_read_bra(struct device *dev, unsigned int addr, memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN], len); err_spi_transfer: - if (tx_buf != bus->tx_buf) + if (tx_buf != goodix_spi_bus.tx_buf) kfree(tx_buf); err_alloc_tx_buf: - if (rx_buf != bus->rx_buf) + if (rx_buf != goodix_spi_bus.rx_buf) kfree(rx_buf); err_alloc_rx_buf: - mutex_unlock(&bus->mutex); + mutex_unlock(&goodix_spi_bus.mutex); return ret; } @@ -121,8 +122,6 @@ static int goodix_spi_read(struct device *dev, unsigned int addr, unsigned char *data, unsigned int len) { struct spi_device *spi = to_spi_device(dev); - struct goodix_ts_core *cd = dev_get_drvdata(dev); - struct goodix_bus_interface *bus = cd->bus; u8 *rx_buf = NULL; u8 *tx_buf = NULL; struct spi_transfer xfers; @@ -130,15 +129,16 @@ static int goodix_spi_read(struct device *dev, unsigned int addr, int ret = 0; int buf_len = SPI_READ_PREFIX_LEN - 1 + len; - if (bus->dma_mode_enabled && buf_len >= 64) + if (goodix_spi_bus.dma_mode_enabled && buf_len >= 64) { buf_len = ALIGN(buf_len, 4); + } - mutex_lock(&bus->mutex); + mutex_lock(&goodix_spi_bus.mutex); if (buf_len <= SPI_PREALLOC_RX_BUF_SIZE && buf_len <= SPI_PREALLOC_TX_BUF_SIZE) { - rx_buf = bus->rx_buf; - tx_buf = bus->tx_buf; + rx_buf = goodix_spi_bus.rx_buf; + tx_buf = goodix_spi_bus.tx_buf; memset(tx_buf, 0, buf_len); } else { rx_buf = kzalloc(buf_len, GFP_KERNEL); @@ -173,8 +173,7 @@ static int goodix_spi_read(struct device *dev, unsigned int addr, xfers.rx_buf = rx_buf; xfers.len = buf_len; xfers.cs_change = 0; - if (bus->dma_mode_enabled) - xfers.bits_per_word = buf_len >= 64 ? 32 : 8; + if (goodix_spi_bus.dma_mode_enabled) xfers.bits_per_word = buf_len >= 64 ? 32 : 8; spi_message_add_tail(&xfers, &spi_msg); ret = spi_sync(spi, &spi_msg); if (ret < 0) { @@ -184,37 +183,32 @@ static int goodix_spi_read(struct device *dev, unsigned int addr, memcpy(data, &rx_buf[SPI_READ_PREFIX_LEN - 1], len); err_spi_transfer: - if (tx_buf != bus->tx_buf) + if (tx_buf != goodix_spi_bus.tx_buf) kfree(tx_buf); err_alloc_tx_buf: - if (rx_buf != bus->rx_buf) + if (rx_buf != goodix_spi_bus.rx_buf) kfree(rx_buf); err_alloc_rx_buf: - mutex_unlock(&bus->mutex); + mutex_unlock(&goodix_spi_bus.mutex); return ret; } -/* [GOOG] - * This SPI transaction will direct read into `struct goodix_rx_package`. - * And, the package are comprised of `SPI prefix header` + `data`. - */ static int goodix_spi_read_fast(struct device *dev, unsigned int addr, struct goodix_rx_package *package, unsigned int len) { struct spi_device *spi = to_spi_device(dev); - struct goodix_ts_core *cd = dev_get_drvdata(dev); - struct goodix_bus_interface *bus = cd->bus; u8 *tx_buf = NULL; struct spi_transfer xfers; struct spi_message spi_msg; int ret = 0; int buf_len = SPI_READ_PREFIX_LEN - 1 + len; - if (bus->dma_mode_enabled && buf_len >= 64) + if (goodix_spi_bus.dma_mode_enabled && buf_len >= 64) { buf_len = ALIGN(buf_len, 4); + } if (buf_len <= SPI_PREALLOC_TX_BUF_SIZE) { - tx_buf = bus->tx_buf; + tx_buf = goodix_spi_bus.tx_buf; } else { tx_buf = kzalloc(buf_len, GFP_KERNEL); if (!tx_buf) { @@ -226,7 +220,7 @@ static int goodix_spi_read_fast(struct device *dev, unsigned int addr, spi_message_init(&spi_msg); memset(&xfers, 0, sizeof(xfers)); - mutex_lock(&bus->mutex); + mutex_lock(&goodix_spi_bus.mutex); /*spi_read tx_buf format: 0xF1 + addr(4bytes) + data*/ tx_buf[0] = SPI_READ_FLAG; @@ -242,13 +236,12 @@ static int goodix_spi_read_fast(struct device *dev, unsigned int addr, xfers.rx_buf = package->header; xfers.len = buf_len; xfers.cs_change = 0; - if (bus->dma_mode_enabled) - xfers.bits_per_word = buf_len >= 64 ? 32 : 8; + if (goodix_spi_bus.dma_mode_enabled) xfers.bits_per_word = buf_len >= 64 ? 32 : 8; spi_message_add_tail(&xfers, &spi_msg); ret = spi_sync(spi, &spi_msg); - mutex_unlock(&bus->mutex); + mutex_unlock(&goodix_spi_bus.mutex); if (ret < 0) { ts_err("spi transfer error:%d", ret); @@ -256,7 +249,7 @@ static int goodix_spi_read_fast(struct device *dev, unsigned int addr, } err_spi_transfer: - if (tx_buf != bus->tx_buf) + if (tx_buf != goodix_spi_bus.tx_buf) kfree(tx_buf); return ret; } @@ -273,19 +266,18 @@ static int goodix_spi_write(struct device *dev, unsigned int addr, unsigned char *data, unsigned int len) { struct spi_device *spi = to_spi_device(dev); - struct goodix_ts_core *cd = dev_get_drvdata(dev); - struct goodix_bus_interface *bus = cd->bus; u8 *tx_buf = NULL; struct spi_transfer xfers; struct spi_message spi_msg; int ret = 0; int buf_len = SPI_WRITE_PREFIX_LEN + len; - if (bus->dma_mode_enabled && buf_len >= 64) + if (goodix_spi_bus.dma_mode_enabled && buf_len >= 64) { buf_len = ALIGN(buf_len, 4); + } if (buf_len <= SPI_PREALLOC_TX_BUF_SIZE) { - tx_buf = bus->tx_buf; + tx_buf = goodix_spi_bus.tx_buf; } else { tx_buf = kzalloc(buf_len, GFP_KERNEL); if (!tx_buf) { @@ -297,7 +289,7 @@ static int goodix_spi_write(struct device *dev, unsigned int addr, spi_message_init(&spi_msg); memset(&xfers, 0, sizeof(xfers)); - mutex_lock(&bus->mutex); + mutex_lock(&goodix_spi_bus.mutex); tx_buf[0] = SPI_WRITE_FLAG; tx_buf[1] = (addr >> 24) & 0xFF; @@ -308,24 +300,28 @@ static int goodix_spi_write(struct device *dev, unsigned int addr, xfers.tx_buf = tx_buf; xfers.len = buf_len; xfers.cs_change = 0; - if (bus->dma_mode_enabled) - xfers.bits_per_word = buf_len >= 64 ? 32 : 8; + if (goodix_spi_bus.dma_mode_enabled) xfers.bits_per_word = buf_len >= 64 ? 32 : 8; spi_message_add_tail(&xfers, &spi_msg); ret = spi_sync(spi, &spi_msg); - mutex_unlock(&bus->mutex); + mutex_unlock(&goodix_spi_bus.mutex); if (ret < 0) ts_err("spi transfer error:%d", ret); - if (tx_buf != bus->tx_buf) + if (tx_buf != goodix_spi_bus.tx_buf) kfree(tx_buf); return ret; } +static void goodix_pdev_release(struct device *dev) +{ + ts_info("goodix pdev released"); + kfree(goodix_pdev); +} + static int goodix_spi_probe(struct spi_device *spi) { - struct goodix_device_resource *dev_res; int ret = 0; ts_info("goodix spi probe in"); @@ -333,7 +329,7 @@ static int goodix_spi_probe(struct spi_device *spi) /* init spi_device */ spi->mode = SPI_MODE_0; spi->bits_per_word = 8; - spi->rt = true; /* [GOOG] */ + spi->rt = true; ret = spi_setup(spi); if (ret) { @@ -341,71 +337,83 @@ static int goodix_spi_probe(struct spi_device *spi) return ret; } - dev_res = kzalloc(sizeof(*dev_res), GFP_KERNEL); - if (!dev_res) - return -ENOMEM; - goodix_device_register(dev_res); - /* get ic type */ - ret = goodix_get_ic_type(spi->dev.of_node, &dev_res->bus); + ret = goodix_get_ic_type(spi->dev.of_node, &goodix_spi_bus); if (ret < 0) - goto err_get_ic_type; + return ret; - dev_res->bus.bus_type = GOODIX_BUS_TYPE_SPI; - dev_res->bus.dev = &spi->dev; - if (dev_res->bus.ic_type == IC_TYPE_BERLIN_A) { - dev_res->bus.read = goodix_spi_read_bra; + goodix_spi_bus.bus_type = GOODIX_BUS_TYPE_SPI; + goodix_spi_bus.dev = &spi->dev; + if (goodix_spi_bus.ic_type == IC_TYPE_BERLIN_A) { + goodix_spi_bus.read = goodix_spi_read_bra; } else { - dev_res->bus.read = goodix_spi_read; - dev_res->bus.read_fast = goodix_spi_read_fast; + goodix_spi_bus.read = goodix_spi_read; + goodix_spi_bus.read_fast = goodix_spi_read_fast; } - dev_res->bus.write = goodix_spi_write; + goodix_spi_bus.write = goodix_spi_write; + goodix_spi_bus.rx_buf = kzalloc(SPI_PREALLOC_RX_BUF_SIZE, GFP_KERNEL); + if (!goodix_spi_bus.rx_buf) { + return -ENOMEM; + } - /* [GOOG] */ - dev_res->bus.rx_buf = kzalloc(SPI_PREALLOC_RX_BUF_SIZE, GFP_KERNEL); - dev_res->bus.tx_buf = kzalloc(SPI_PREALLOC_TX_BUF_SIZE, GFP_KERNEL); - if (!dev_res->bus.rx_buf || !dev_res->bus.tx_buf) { + goodix_spi_bus.tx_buf = kzalloc(SPI_PREALLOC_TX_BUF_SIZE, GFP_KERNEL); + if (!goodix_spi_bus.tx_buf) { ret = -ENOMEM; - goto err_pdev; + goto err_alloc_tx_buf; } - mutex_init(&dev_res->bus.mutex); - dev_res->bus.dma_mode_enabled = false; + mutex_init(&goodix_spi_bus.mutex); + + goodix_spi_bus.dma_mode_enabled = false; #ifdef CONFIG_GOOG_TOUCH_INTERFACE - dev_res->bus.dma_mode_enabled = goog_check_spi_dma_enabled(spi); - ts_info("dma_mode: %s\n", dev_res->bus.dma_mode_enabled ? "enabled" : "disabled"); + goodix_spi_bus.dma_mode_enabled = goog_check_spi_dma_enabled(spi); + ts_info("dma_mode: %s\n", goodix_spi_bus.dma_mode_enabled ? "enabled" : "disabled"); #endif - // platform device init - dev_res->pdev.name = GOODIX_CORE_DRIVER_NAME; - dev_res->pdev.id = dev_res->id; - dev_res->pdev.num_resources = 0; + /* ts core device */ + goodix_pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + if (!goodix_pdev) { + ret = -ENOMEM; + goto err_alloc_pdev; + } + + goodix_pdev->name = GOODIX_CORE_DRIVER_NAME; + goodix_pdev->id = 0; + goodix_pdev->num_resources = 0; + /* + * you can find this platform dev in + * /sys/devices/platform/goodix_ts.0 + * goodix_pdev->dev.parent = &client->dev; + */ + goodix_pdev->dev.platform_data = &goodix_spi_bus; + goodix_pdev->dev.release = goodix_pdev_release; /* register platform device, then the goodix_ts_core * module will probe the touch device. */ - ret = platform_device_register(&dev_res->pdev); + ret = platform_device_register(goodix_pdev); if (ret) { ts_err("failed register goodix platform device, %d", ret); - goto err_pdev; + goto err_register_platform_device; } ts_info("spi probe out"); return 0; -err_pdev: - kfree(dev_res->bus.rx_buf); - kfree(dev_res->bus.tx_buf); -err_get_ic_type: - kfree(dev_res); +err_register_platform_device: + kfree(goodix_pdev); +err_alloc_pdev: + kfree(goodix_spi_bus.tx_buf); +err_alloc_tx_buf: + kfree(goodix_spi_bus.rx_buf); + ts_info("spi probe out, %d", ret); return ret; } static int goodix_spi_remove(struct spi_device *spi) { - /* goodix_ts_core_exit() will unregister device(s) */ - // platform_device_unregister(dev_res->pdev); + platform_device_unregister(goodix_pdev); return 0; } diff --git a/goodix_cfg_bin.c b/goodix_cfg_bin.c index ab24e6a..f7fef30 100644 --- a/goodix_cfg_bin.c +++ b/goodix_cfg_bin.c @@ -114,7 +114,7 @@ static int goodix_read_cfg_bin(struct device *dev, const char *cfg_name, if (!ret) break; ts_info("get cfg bin retry:[%d]", GOODIX_RETRY_3 - retry); - msleep(300); + msleep(200); } if (retry < 0) { ts_err("failed get cfg bin[%s] error:%d", cfg_name, ret); diff --git a/goodix_ts_core.c b/goodix_ts_core.c index 20c317d..120c4f5 100644 --- a/goodix_ts_core.c +++ b/goodix_ts_core.c @@ -31,60 +31,257 @@ // #include "../../../video/fbdev/core/fb_firefly.h" #define GOODIX_DEFAULT_CFG_NAME "goodix_cfg_group.cfg" +#define GOOIDX_INPUT_PHYS "goodix_ts/input0" -struct goodix_device_manager goodix_devices; +struct goodix_module goodix_modules; +int core_module_prob_sate = CORE_MODULE_UNPROBED; -static const struct dev_pm_ops dev_pm_ops; /* [GOOG] */ +static const struct dev_pm_ops dev_pm_ops; -static void goodix_device_manager_init(void) +static int goodix_send_ic_config(struct goodix_ts_core *cd, int type); +/** + * __do_register_ext_module - register external module + * to register into touch core modules structure + * return 0 on success, otherwise return < 0 + */ +static int __do_register_ext_module(struct goodix_ext_module *module) { - if (goodix_devices.initialized) + struct goodix_ext_module *ext_module, *next; + struct list_head *insert_point = &goodix_modules.head; + + /* prority level *must* be set */ + if (module->priority == EXTMOD_PRIO_RESERVED) { + ts_err("Priority of module [%s] needs to be set", module->name); + return -EINVAL; + } + mutex_lock(&goodix_modules.mutex); + /* find insert point for the specified priority */ + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (ext_module == module) { + ts_info("Module [%s] already exists", + module->name); + mutex_unlock(&goodix_modules.mutex); + return 0; + } + } + + /* smaller priority value with higher priority level */ + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (ext_module->priority >= module->priority) { + insert_point = &ext_module->list; + break; + } + } + } + + if (module->funcs && module->funcs->init) { + if (module->funcs->init(goodix_modules.core_data, module) < 0) { + ts_err("Module [%s] init error", + module->name ? module->name : " "); + mutex_unlock(&goodix_modules.mutex); + return -EFAULT; + } + } + + list_add(&module->list, insert_point->prev); + mutex_unlock(&goodix_modules.mutex); + + return 0; +} + +static void goodix_register_ext_module_work(struct work_struct *work) +{ + struct goodix_ext_module *module = + container_of(work, struct goodix_ext_module, work); + + ts_info("module register work IN"); + + /* driver probe failed */ + if (core_module_prob_sate != CORE_MODULE_PROB_SUCCESS) { + ts_err("Can't register ext_module core error"); return; - goodix_devices.initialized = true; - INIT_LIST_HEAD(&goodix_devices.list); - mutex_init(&goodix_devices.mutex); + } + + if (__do_register_ext_module(module)) + ts_err("failed register module: %s", module->name); + else + ts_info("success register module: %s", module->name); } -static void goodix_device_manager_exit(void) +static void goodix_core_module_init(void) { - struct goodix_device_resource *res, *next; + if (goodix_modules.initialized) + return; + goodix_modules.initialized = true; + INIT_LIST_HEAD(&goodix_modules.head); + mutex_init(&goodix_modules.mutex); +} - if (!list_empty(&goodix_devices.list)) { - list_for_each_entry_safe(res, next, &goodix_devices.list, list) { - platform_device_unregister(&res->pdev); - kfree(res); - } +/** + * goodix_register_ext_module - interface for register external module + * to the core. This will create a workqueue to finish the real register + * work and return immediately. The user need to check the final result + * to make sure registe is success or fail. + * + * @module: pointer to external module to be register + * return: 0 ok, <0 failed + */ +int goodix_register_ext_module(struct goodix_ext_module *module) +{ + if (!module) + return -EINVAL; + + ts_info("IN"); + + goodix_core_module_init(); + INIT_WORK(&module->work, goodix_register_ext_module_work); + schedule_work(&module->work); + + ts_info("OUT"); + return 0; +} + +/** + * goodix_register_ext_module_no_wait + * return: 0 ok, <0 failed + */ +int goodix_register_ext_module_no_wait(struct goodix_ext_module *module) +{ + if (!module) + return -EINVAL; + + ts_info("IN"); + goodix_core_module_init(); + /* driver probe failed */ + if (core_module_prob_sate != CORE_MODULE_PROB_SUCCESS) { + ts_err("Can't register ext_module core error"); + return -EINVAL; } + return __do_register_ext_module(module); } -int goodix_device_register(struct goodix_device_resource *device) +/** + * goodix_unregister_ext_module - interface for external module + * to unregister external modules + * + * @module: pointer to external module + * return: 0 ok, <0 failed + */ +int goodix_unregister_ext_module(struct goodix_ext_module *module) { - if (!device) - return -ENXIO; + struct goodix_ext_module *ext_module, *next; + bool found = false; + + if (!module) + return -EINVAL; - mutex_lock(&goodix_devices.mutex); - list_add(&device->list, &goodix_devices.list); - device->id = goodix_devices.nums++; - sprintf(device->name, "%s.%d", GOODIX_CORE_DRIVER_NAME, device->id); - mutex_unlock(&goodix_devices.mutex); - ts_info("register device %s", device->name); + if (!goodix_modules.initialized) + return -EINVAL; + + if (!goodix_modules.core_data) + return -ENODEV; + mutex_lock(&goodix_modules.mutex); + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (ext_module == module) { + found = true; + break; + } + } + } else { + mutex_unlock(&goodix_modules.mutex); + return 0; + } + + if (!found) { + ts_debug("Module [%s] never registed", module->name); + mutex_unlock(&goodix_modules.mutex); + return 0; + } + + list_del(&module->list); + mutex_unlock(&goodix_modules.mutex); + + if (module->funcs && module->funcs->exit) + module->funcs->exit(goodix_modules.core_data, module); + + ts_info("Module [%s] unregistered", module->name ? module->name : " "); return 0; } -static int goodix_send_ic_config(struct goodix_ts_core *cd, int type); +static void goodix_ext_sysfs_release(struct kobject *kobj) +{ + ts_info("Kobject released!"); +} + +#define to_ext_module(kobj) container_of(kobj, struct goodix_ext_module, kobj) +#define to_ext_attr(attr) container_of(attr, struct goodix_ext_attribute, attr) + +static ssize_t goodix_ext_sysfs_show( + struct kobject *kobj, struct attribute *attr, char *buf) +{ + struct goodix_ext_module *module = to_ext_module(kobj); + struct goodix_ext_attribute *ext_attr = to_ext_attr(attr); + + if (ext_attr->show) + return ext_attr->show(module, buf); + + return -EIO; +} + +static ssize_t goodix_ext_sysfs_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + struct goodix_ext_module *module = to_ext_module(kobj); + struct goodix_ext_attribute *ext_attr = to_ext_attr(attr); + + if (ext_attr->store) + return ext_attr->store(module, buf, count); + + return -EIO; +} + +static const struct sysfs_ops goodix_ext_ops = { .show = goodix_ext_sysfs_show, + .store = goodix_ext_sysfs_store }; + +static struct kobj_type goodix_ext_ktype = { + .release = goodix_ext_sysfs_release, + .sysfs_ops = &goodix_ext_ops, +}; + +struct kobj_type *goodix_get_default_ktype(void) +{ + return &goodix_ext_ktype; +} + +struct kobject *goodix_get_default_kobj(void) +{ + struct kobject *kobj = NULL; + + if (goodix_modules.core_data && goodix_modules.core_data->pdev) + kobj = &goodix_modules.core_data->pdev->dev.kobj; + return kobj; +} /* show driver information */ -static ssize_t driver_info_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t driver_info_show( + struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "DriverVersion:%s\n", - GOODIX_DRIVER_VERSION); + return snprintf( + buf, PAGE_SIZE, "DriverVersion:%s\n", GOODIX_DRIVER_VERSION); } /* show chip infoamtion */ -static ssize_t chip_info_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t chip_info_show( + struct device *dev, struct device_attribute *attr, char *buf) { struct goodix_ts_core *cd = dev_get_drvdata(dev); struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; @@ -473,15 +670,13 @@ static ssize_t goodix_ts_esd_info_show( static ssize_t goodix_ts_esd_info_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct goodix_ts_core *cd = dev_get_drvdata(dev); - if (!buf || count <= 0) return -EINVAL; if (buf[0] != '0') - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); else - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); return count; } @@ -511,19 +706,35 @@ static ssize_t goodix_ts_debug_log_store(struct device *dev, return count; } +#define GOODIX_MAX_PEN_FREQ_DATA_LEN 16 +#define GOODIX_HOGP_INFO_LEN 3 + +#pragma pack(1) +struct goodix_hid_hogp { + u16 pressure; + u8 key; +}; +#pragma pack() + +struct goodix_ble_data { + u8 freq[GOODIX_MAX_PEN_FREQ_DATA_LEN]; + u8 hogp[GOODIX_HOGP_INFO_LEN]; + int hogp_ready; + int freq_ready; + struct mutex lock; +} goodix_ble_data; + int goodix_update_pen_freq(struct goodix_ts_core *cd, u8 *data, int len) { - struct goodix_ble_data *ble_data = &cd->ble_data; - - if (len > sizeof(ble_data->freq)) { + if (len > sizeof(goodix_ble_data.freq)) { ts_err("pen freq data exceed limit"); return -EINVAL; } - mutex_lock(&ble_data->lock); - memset(ble_data->freq, 0, sizeof(ble_data->freq)); - memcpy(ble_data->freq, data, len); - ble_data->freq_ready = 1; - mutex_unlock(&ble_data->lock); + mutex_lock(&goodix_ble_data.lock); + memset(goodix_ble_data.freq, 0, sizeof(goodix_ble_data.freq)); + memcpy(goodix_ble_data.freq, data, len); + goodix_ble_data.freq_ready = 1; + mutex_unlock(&goodix_ble_data.lock); sysfs_notify(&cd->pdev->dev.kobj, NULL, "pen_freq"); ts_debug("send pen freq hop event"); return 0; @@ -533,14 +744,11 @@ int goodix_update_pen_freq(struct goodix_ts_core *cd, u8 *data, int len) static ssize_t goodix_ts_pen_freq_show( struct device *dev, struct device_attribute *attr, char *buf) { - struct goodix_ts_core *core_data = dev_get_drvdata(dev); - struct goodix_ble_data *ble_data = &core_data->ble_data; - - mutex_lock(&ble_data->lock); - memcpy(buf, ble_data->freq, sizeof(ble_data->freq)); - ble_data->freq_ready = 0; - mutex_unlock(&ble_data->lock); - return sizeof(ble_data->freq); + mutex_lock(&goodix_ble_data.lock); + memcpy(buf, goodix_ble_data.freq, sizeof(goodix_ble_data.freq)); + goodix_ble_data.freq_ready = 0; + mutex_unlock(&goodix_ble_data.lock); + return sizeof(goodix_ble_data.freq); } /* debug level store */ @@ -549,13 +757,12 @@ static ssize_t goodix_ts_pen_debug_store(struct device *dev, { int pen_freq; struct goodix_ts_core *core_data = dev_get_drvdata(dev); - struct goodix_ble_data *ble_data = &core_data->ble_data; sscanf(buf, "%d", &pen_freq); ts_debug("set new pen_freq %d", pen_freq); - ble_data->freq[0] = 0xC0; - ble_data->freq[1] = 1; - ble_data->freq[2] = pen_freq & 0xFF; + goodix_ble_data.freq[0] = 0xC0; + goodix_ble_data.freq[1] = 1; + goodix_ble_data.freq[2] = pen_freq & 0xFF; sysfs_notify(&core_data->pdev->dev.kobj, NULL, "pen_freq"); return count; @@ -565,20 +772,18 @@ static ssize_t goodix_ts_pen_hogp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct goodix_hid_hogp *tmp_prs; - struct goodix_ts_core *core_data = dev_get_drvdata(dev); - struct goodix_ble_data *ble_data = &core_data->ble_data; - if (count < sizeof(ble_data->hogp)) { + if (count < sizeof(goodix_ble_data.hogp)) { ts_err("data count to short"); return -EINVAL; } - mutex_lock(&ble_data->lock); - memcpy(ble_data->hogp, buf, sizeof(ble_data->hogp)); - ble_data->hogp_ready = 1; - mutex_unlock(&ble_data->lock); + mutex_lock(&goodix_ble_data.lock); + memcpy(goodix_ble_data.hogp, buf, sizeof(goodix_ble_data.hogp)); + goodix_ble_data.hogp_ready = 1; + mutex_unlock(&goodix_ble_data.lock); - tmp_prs = (struct goodix_hid_hogp *)ble_data->hogp; + tmp_prs = (struct goodix_hid_hogp *)goodix_ble_data.hogp; ts_debug("set ble pen data: %d, key %x", tmp_prs->pressure, tmp_prs->key); return count; @@ -636,7 +841,6 @@ static void goodix_ts_sysfs_exit(struct goodix_ts_core *core_data) sysfs_remove_group(&core_data->pdev->dev.kobj, &sysfs_group); } -/* [GOOG] */ #if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) int set_continuously_report_enabled(struct device *dev, bool enabled) { @@ -703,10 +907,10 @@ int set_sensing_enabled(struct device *dev, bool enabled) if (enabled) { cd->hw_ops->resume(cd); cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); ts_info("set sense ON"); } else { - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); cd->hw_ops->irq_enable(cd, false); cd->hw_ops->suspend(cd); ts_info("set sense OFF"); @@ -765,8 +969,8 @@ static int get_mutual_sensor_data( cmd->buffer = (u8 *)cd->mutual_data; cmd->size = tx * rx * sizeof(uint16_t); } else { - /* disable esd */ - goodix_ts_esd_off(cd); + /* close esd */ + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); ret = -EINVAL; if (cmd->type == GTI_SENSOR_DATA_TYPE_MS_DIFF) { @@ -781,8 +985,9 @@ static int get_mutual_sensor_data( cmd->buffer = (u8 *)cd->mutual_data_manual; cmd->size = tx * rx * sizeof(uint16_t); } + /* enable esd */ - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); } return ret; } @@ -801,7 +1006,7 @@ static int get_self_sensor_data( } else { /* disable irq & close esd */ cd->hw_ops->irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); ret = -EINVAL; if (cmd->type == GTI_SENSOR_DATA_TYPE_SS_DIFF) { @@ -819,7 +1024,7 @@ static int get_self_sensor_data( /* enable irq & esd */ cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); } return ret; } @@ -983,10 +1188,8 @@ static int gti_ping(void *private_data, struct gti_ping_cmd *cmd) static int gti_selftest(void *private_data, struct gti_selftest_cmd *cmd) { - struct goodix_ts_core *cd = private_data; - cmd->result = GTI_SELFTEST_RESULT_DONE; - return driver_test_selftest(cd, cmd->buffer); + return driver_test_selftest(cmd->buffer); } static int gti_get_context_driver(void *private_data, @@ -1004,7 +1207,6 @@ static int gti_set_report_rate(void *private_data, } #endif -/*~[GOOG] */ /* prosfs create */ static int rawdata_proc_show(struct seq_file *m, void *v) @@ -1055,8 +1257,8 @@ exit: static int rawdata_proc_open(struct inode *inode, struct file *file) { - return single_open_size(file, rawdata_proc_show, - PDE_DATA(inode), PAGE_SIZE * 10); + return single_open_size( + file, rawdata_proc_show, PDE_DATA(inode), PAGE_SIZE * 10); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) @@ -1077,51 +1279,78 @@ static const struct file_operations rawdata_proc_fops = { static int goodix_ts_procfs_init(struct goodix_ts_core *core_data) { - int dev_id = core_data->pdev->id; struct proc_dir_entry *proc_entry; - char proc_node[32] = {0}; - int ret = 0; /* [GOOG] */ - - sprintf(proc_node, "goodix_ts.%d", dev_id); + int ret = 0; - core_data->proc_dir_entry = proc_mkdir(proc_node, NULL); - if (!core_data->proc_dir_entry) + proc_entry = proc_mkdir("goodix_ts", NULL); + if (proc_entry == NULL) { + ts_err("failed to create proc entry: goodix_ts"); return -ENOMEM; - proc_entry = proc_create_data("tp_capacitance_data", - 0664, core_data->proc_dir_entry, &rawdata_proc_fops, core_data); - if (!proc_entry) { - ts_err("failed to create proc entry: goodix_ts.%d/tp_capacitance_data", - dev_id); + } + + proc_entry = proc_create_data("goodix_ts/tp_capacitance_data", 0664, + NULL, &rawdata_proc_fops, core_data); + if (proc_entry == NULL) { + ts_err("failed to create proc entry: goodix_ts/tp_capacitance_data"); ret = -ENOMEM; goto err_create_data; } ret = driver_test_proc_init(core_data); if (ret != 0) { - ts_err("failed to create proc entry: goodix_ts.%d/driver_test", dev_id); + ts_err("failed to create proc entry: goodix_ts/driver_test"); ret = -ENOMEM; goto err_create_driver; } - - return 0; + return ret; err_create_driver: - remove_proc_entry("tp_capacitance_data", core_data->proc_dir_entry); + remove_proc_entry("goodix_ts/tp_capacitance_data", NULL); err_create_data: - remove_proc_entry(proc_node, NULL); + remove_proc_entry("goodix_ts", NULL); return ret; } static void goodix_ts_procfs_exit(struct goodix_ts_core *core_data) { - int dev_id = core_data->pdev->id; - char proc_node[32] = {0}; + driver_test_proc_remove(); + remove_proc_entry("goodix_ts/tp_capacitance_data", NULL); + remove_proc_entry("goodix_ts", NULL); +} - sprintf(proc_node, "goodix_ts.%d", dev_id); +/* event notifier */ +static BLOCKING_NOTIFIER_HEAD(ts_notifier_list); +/** + * goodix_ts_register_client - register a client notifier + * @nb: notifier block to callback on events + * see enum ts_notify_event in goodix_ts_core.h + */ +int goodix_ts_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&ts_notifier_list, nb); +} - driver_test_proc_remove(core_data); - remove_proc_entry("tp_capacitance_data", core_data->proc_dir_entry); - remove_proc_entry(proc_node, NULL); +/** + * goodix_ts_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + * see enum ts_notify_event in goodix_ts_core.h + */ +int goodix_ts_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&ts_notifier_list, nb); +} + +/** + * fb_notifier_call_chain - notify clients of fb_events + * see enum ts_notify_event in goodix_ts_core.h + */ +int goodix_ts_blocking_notify(enum ts_notify_event evt, void *v) +{ + int ret; + + ret = blocking_notifier_call_chain( + &ts_notifier_list, (unsigned long)evt, v); + return ret; } #if IS_ENABLED(CONFIG_OF) @@ -1390,8 +1619,8 @@ static void goodix_ts_report_pen( { struct input_dev *dev = cd->pen_dev; int i; + static unsigned int pen_pressure; struct goodix_hid_hogp *hogp; - struct goodix_ble_data *ble_data = &cd->ble_data; char trace_tag[128]; ktime_t pen_ktime; @@ -1406,21 +1635,21 @@ static void goodix_ts_report_pen( ktime_to_ns(ktime_sub(pen_ktime, cd->coords_timestamp))); ATRACE_BEGIN(trace_tag); input_report_key(dev, BTN_TOUCH, 1); - input_report_key(dev, BTN_TOOL_PEN, 1); + input_report_key(dev, pen_data->coords.tool_type, 1); input_report_abs(dev, ABS_X, pen_data->coords.x); input_report_abs(dev, ABS_Y, pen_data->coords.y); - mutex_lock(&ble_data->lock); - if (ble_data->hogp_ready) { - hogp = (struct goodix_hid_hogp *)ble_data->hogp; - cd->pen_pressure = hogp->pressure; + mutex_lock(&goodix_ble_data.lock); + if (goodix_ble_data.hogp_ready) { + hogp = (struct goodix_hid_hogp *)goodix_ble_data.hogp; + pen_pressure = hogp->pressure; ts_debug("update pen pressure from ble %d", - cd->pen_pressure); + pen_pressure); } - ble_data->hogp_ready = 0; - mutex_unlock(&ble_data->lock); + goodix_ble_data.hogp_ready = 0; + mutex_unlock(&goodix_ble_data.lock); - if (pen_data->coords.p && cd->pen_pressure) - pen_data->coords.p = cd->pen_pressure; + if (pen_data->coords.p && pen_pressure) + pen_data->coords.p = pen_pressure; input_report_abs(dev, ABS_PRESSURE, pen_data->coords.p); if (pen_data->coords.p == 0) input_report_abs(dev, ABS_DISTANCE, 1); @@ -1441,9 +1670,9 @@ static void goodix_ts_report_pen( ktime_to_ns(cd->coords_timestamp), ktime_to_ns(pen_ktime), ktime_to_ns(ktime_sub(pen_ktime, cd->coords_timestamp))); ATRACE_BEGIN(trace_tag); - cd->pen_pressure = 0; + pen_pressure = 0; input_report_key(dev, BTN_TOUCH, 0); - input_report_key(dev, BTN_TOOL_PEN, 0); + input_report_key(dev, pen_data->coords.tool_type, 0); } /* report pen button */ for (i = 0; i < GOODIX_MAX_PEN_KEY; i++) { @@ -1621,8 +1850,9 @@ static int goodix_ts_request_handle( else if (ts_event->request_code == REQUEST_TYPE_RESET) ret = hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS); else if (ts_event->request_code == REQUEST_TYPE_UPDATE) - ret = goodix_do_fw_update(cd, UPDATE_MODE_FORCE | UPDATE_MODE_BLOCK | - UPDATE_MODE_SRC_REQUEST); + ret = goodix_do_fw_update( + NULL, UPDATE_MODE_FORCE | UPDATE_MODE_BLOCK | + UPDATE_MODE_SRC_REQUEST); else if (ts_event->request_code == REQUEST_PEN_FREQ_HOP) ret = goodix_update_pen_freq(cd, ts_event->request_data, sizeof(ts_event->request_data)); @@ -1719,6 +1949,7 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) { struct goodix_ts_core *core_data = data; struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; + struct goodix_ext_module *ext_module, *next; struct goodix_ts_event *ts_event = &core_data->ts_event; struct goodix_ts_esd *ts_esd = &core_data->ts_esd; int ret; @@ -1731,18 +1962,29 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) } #endif -/* [GOOG] - * Remove the control to enable/disable the interrupt for bottom-half. - disable_irq_nosync(core_data->irq); - */ - - /* [GOOG] + /* * Since we received an interrupt from touch firmware, it means touch * firmware is still alive. So skip esd check once. */ ts_esd->skip_once = true; core_data->irq_trig_cnt++; + /* inform external module */ + mutex_lock(&goodix_modules.mutex); + list_for_each_entry_safe(ext_module, next, &goodix_modules.head, list) + { + if (!ext_module->funcs->irq_event) + continue; + ret = ext_module->funcs->irq_event(core_data, ext_module); + if (ret == EVT_CANCEL_IRQEVT) { + mutex_unlock(&goodix_modules.mutex); +#if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) && IS_ENABLED(CONFIG_GTI_PM) + goog_pm_wake_unlock_nosync(core_data->gti, GTI_PM_WAKELOCK_TYPE_IRQ); +#endif + return IRQ_HANDLED; + } + } + mutex_unlock(&goodix_modules.mutex); /* read touch data from touch device */ ret = hw_ops->event_handler(core_data, ts_event); @@ -1770,16 +2012,10 @@ static irqreturn_t goodix_ts_threadirq_func(int irq, void *data) goodix_ts_request_handle(core_data, ts_event); if (ts_event->event_type & EVENT_STATUS) goodix_ts_report_status(core_data, ts_event); - if (ts_event->event_type & EVENT_GESTURE) - goodix_ts_report_gesture(core_data, ts_event); /* read done */ - hw_ops->after_event_handler(core_data); /* [GOOG] */ + hw_ops->after_event_handler(core_data); } -/* [GOOG] - * Remove the control to enable/disable the interrupt for bottom-half. - enable_irq(core_data->irq); - */ #if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) && IS_ENABLED(CONFIG_GTI_PM) goog_pm_wake_unlock_nosync(core_data->gti, GTI_PM_WAKELOCK_TYPE_IRQ); @@ -2004,7 +2240,6 @@ static int goodix_ts_input_dev_config(struct goodix_ts_core *core_data) { struct goodix_ts_board_data *ts_bdata = board_data(core_data); struct input_dev *input_dev = NULL; - int dev_id = core_data->pdev->id; int r; input_dev = input_allocate_device(); @@ -2013,15 +2248,12 @@ static int goodix_ts_input_dev_config(struct goodix_ts_core *core_data) return -ENOMEM; } - sprintf(core_data->input_name, "%s%d", GOODIX_CORE_DRIVER_NAME, dev_id); - input_dev->dev.parent = &core_data->pdev->dev; /* [GOOG] */ - input_dev->name = core_data->input_name; - input_dev->uniq = input_dev->name; - input_dev->phys = input_dev->name; - input_dev->id.bustype = core_data->bus->bus_type; - input_dev->id.product = 0x0100 + dev_id; - input_dev->id.vendor = 0x27C6; - input_dev->id.version = 0x0100; + input_dev->name = GOODIX_CORE_DRIVER_NAME; + input_dev->phys = GOOIDX_INPUT_PHYS; + input_dev->uniq = "goodix_ts"; + input_dev->id.product = 0xDEAD; + input_dev->id.vendor = 0xBEEF; + input_dev->id.version = 10427; set_bit(EV_SYN, input_dev->evbit); set_bit(EV_KEY, input_dev->evbit); @@ -2070,7 +2302,6 @@ static int goodix_ts_pen_dev_config(struct goodix_ts_core *core_data) { struct goodix_ts_board_data *ts_bdata = board_data(core_data); struct input_dev *pen_dev = NULL; - int dev_id = core_data->pdev->id; int r; pen_dev = input_allocate_device(); @@ -2079,15 +2310,12 @@ static int goodix_ts_pen_dev_config(struct goodix_ts_core *core_data) return -ENOMEM; } - sprintf(core_data->input_pen_name, "%s%d%s", GOODIX_CORE_DRIVER_NAME, dev_id, ",pen"); - pen_dev->dev.parent = &core_data->pdev->dev; /* [GOOG] */ - pen_dev->name = core_data->input_pen_name; - pen_dev->uniq = pen_dev->name; - pen_dev->phys = pen_dev->name; - pen_dev->id.bustype = core_data->bus->bus_type; - pen_dev->id.product = 0x0200 + dev_id; - pen_dev->id.vendor = 0x27C6; - pen_dev->id.version = 0x0100; + pen_dev->name = GOODIX_PEN_DRIVER_NAME; + pen_dev->phys = "goodix_ts,pen/input0"; + pen_dev->uniq = "goodix_ts,pen"; + pen_dev->id.product = 0xDEAD; + pen_dev->id.vendor = 0xBEEF; + pen_dev->id.version = 10427; pen_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); set_bit(ABS_X, pen_dev->absbit); @@ -2134,7 +2362,7 @@ void goodix_ts_pen_dev_remove(struct goodix_ts_core *core_data) { if (!core_data->pen_dev) return; - mutex_destroy(&core_data->ble_data.lock); + mutex_destroy(&goodix_ble_data.lock); input_unregister_device(core_data->pen_dev); core_data->pen_dev = NULL; } @@ -2192,7 +2420,7 @@ exit: /** * goodix_ts_esd_on - turn on esd protection */ -void goodix_ts_esd_on(struct goodix_ts_core *cd) +static void goodix_ts_esd_on(struct goodix_ts_core *cd) { struct goodix_ic_info_misc *misc = &cd->ic_info.misc; struct goodix_ts_esd *ts_esd = &cd->ts_esd; @@ -2213,7 +2441,7 @@ void goodix_ts_esd_on(struct goodix_ts_core *cd) /** * goodix_ts_esd_off - turn off esd protection */ -void goodix_ts_esd_off(struct goodix_ts_core *cd) +static void goodix_ts_esd_off(struct goodix_ts_core *cd) { struct goodix_ts_esd *ts_esd = &cd->ts_esd; int ret; @@ -2227,6 +2455,40 @@ void goodix_ts_esd_off(struct goodix_ts_core *cd) } /** + * goodix_esd_notifier_callback - notification callback + * under certain condition, we need to turn off/on the esd + * protector, we use kernel notify call chain to achieve this. + * + * for example: before firmware update we need to turn off the + * esd protector and after firmware update finished, we should + * turn on the esd protector. + */ +static int goodix_esd_notifier_callback( + struct notifier_block *nb, unsigned long action, void *data) +{ + struct goodix_ts_esd *ts_esd = + container_of(nb, struct goodix_ts_esd, esd_notifier); + + switch (action) { + case NOTIFY_FWUPDATE_START: + case NOTIFY_SUSPEND: + case NOTIFY_ESD_OFF: + goodix_ts_esd_off(ts_esd->ts_core); + break; + case NOTIFY_FWUPDATE_FAILED: + case NOTIFY_FWUPDATE_SUCCESS: + case NOTIFY_RESUME: + case NOTIFY_ESD_ON: + goodix_ts_esd_on(ts_esd->ts_core); + break; + default: + break; + } + + return 0; +} + +/** * goodix_ts_esd_init - initialize esd protection */ int goodix_ts_esd_init(struct goodix_ts_core *cd) @@ -2242,6 +2504,8 @@ int goodix_ts_esd_init(struct goodix_ts_core *cd) INIT_DELAYED_WORK(&ts_esd->esd_work, goodix_ts_esd_work); ts_esd->ts_core = cd; atomic_set(&ts_esd->esd_on, 0); + ts_esd->esd_notifier.notifier_call = goodix_esd_notifier_callback; + goodix_ts_register_notifier(&ts_esd->esd_notifier); goodix_ts_esd_on(cd); return 0; @@ -2252,13 +2516,10 @@ void goodix_ts_esd_uninit(struct goodix_ts_core *cd) struct goodix_ts_esd *ts_esd = &cd->ts_esd; if (atomic_read(&ts_esd->esd_on)) goodix_ts_esd_off(cd); + goodix_ts_unregister_notifier(&ts_esd->esd_notifier); } -#if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) -static void goodix_ts_release_connects(struct goodix_ts_core *core_data) -{ -} -#else +#if !IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) static void goodix_ts_release_connects(struct goodix_ts_core *core_data) { struct input_dev *input_dev = core_data->input_dev; @@ -2284,7 +2545,9 @@ static void goodix_ts_release_connects(struct goodix_ts_core *core_data) */ static int goodix_ts_suspend(struct goodix_ts_core *core_data) { + struct goodix_ext_module *ext_module, *next; struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; + int ret; if (core_data->init_stage < CORE_INIT_STAGE2 || atomic_read(&core_data->suspended)) @@ -2294,23 +2557,68 @@ static int goodix_ts_suspend(struct goodix_ts_core *core_data) atomic_set(&core_data->suspended, 1); /* disable irq */ hw_ops->disable_irq_nosync(core_data); - goodix_ts_esd_off(core_data); - if (core_data->gesture_type) { - /* enter gesture mode */ - hw_ops->gesture(core_data, 0); - hw_ops->irq_enable(core_data, true); - enable_irq_wake(core_data->irq); - } else { - /* enter sleep mode or power off */ - if (core_data->board_data.sleep_enable) - hw_ops->suspend(core_data); - else - goodix_ts_power_off(core_data); + /* + * notify suspend event, inform the esd protector + * and charger detector to turn off the work + */ + goodix_ts_blocking_notify(NOTIFY_SUSPEND, NULL); + + /* inform external module */ + mutex_lock(&goodix_modules.mutex); + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (!ext_module->funcs->before_suspend) + continue; + + ret = ext_module->funcs->before_suspend( + core_data, ext_module); + if (ret == EVT_CANCEL_SUSPEND) { + mutex_unlock(&goodix_modules.mutex); + ts_info("Canceled by module:%s", + ext_module->name); + goto out; + } + } } + mutex_unlock(&goodix_modules.mutex); + + /* enter sleep mode or power off */ + 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); + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (!ext_module->funcs->after_suspend) + continue; + + ret = ext_module->funcs->after_suspend( + core_data, ext_module); + if (ret == EVT_CANCEL_SUSPEND) { + mutex_unlock(&goodix_modules.mutex); + ts_info("Canceled by module:%s", + ext_module->name); + goto out; + } + } + } + mutex_unlock(&goodix_modules.mutex); + + goodix_set_pinctrl_state(core_data, PINCTRL_MODE_SUSPEND); + +out: +#if !IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) goodix_ts_release_connects(core_data); +#endif - goodix_set_pinctrl_state(core_data, PINCTRL_MODE_SUSPEND); /* [GOOG] */ ts_info("Suspend end"); return 0; } @@ -2366,44 +2674,80 @@ static void monitor_gesture_event(struct work_struct *work) */ static int goodix_ts_resume(struct goodix_ts_core *core_data) { + struct goodix_ext_module *ext_module, *next; struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; + struct goodix_gesture_data* gesture_data = &core_data->ts_event.gesture_data; + int ret; + if (core_data->init_stage < CORE_INIT_STAGE2 || !atomic_read(&core_data->suspended)) return 0; ts_info("Resume start"); - goodix_set_pinctrl_state(core_data, PINCTRL_MODE_ACTIVE); /* [GOOG] */ + goodix_set_pinctrl_state(core_data, PINCTRL_MODE_ACTIVE); atomic_set(&core_data->suspended, 0); hw_ops->irq_enable(core_data, false); - /* [GOOG] */ - if (check_gesture_mode(core_data)) { - struct goodix_gesture_data *gesture_data = - &core_data->ts_event.gesture_data; + mutex_lock(&goodix_modules.mutex); + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (!ext_module->funcs->before_resume) + continue; + + ret = ext_module->funcs->before_resume( + core_data, ext_module); + if (ret == EVT_CANCEL_RESUME) { + mutex_unlock(&goodix_modules.mutex); + ts_info("Canceled by module:%s", + ext_module->name); + goto out; + } + } + } + mutex_unlock(&goodix_modules.mutex); + if (check_gesture_mode(core_data)) { gesture_data->gesture_type = GOODIX_GESTURE_UNKNOWN; core_data->gesture_down_timeout = ktime_add_ms(ktime_get(), 100); core_data->gesture_up_timeout = ktime_add_ms(ktime_get(), 200); queue_delayed_work(core_data->event_wq, &core_data->monitor_gesture_work, msecs_to_jiffies(5)); } else { - if (core_data->gesture_type) { - disable_irq_wake(core_data->irq); + /* reset device or power on*/ + if (core_data->board_data.sleep_enable) hw_ops->reset(core_data, GOODIX_NORMAL_RESET_DELAY_MS); - } else { - /* reset device or power on*/ - if (core_data->board_data.sleep_enable) - hw_ops->resume(core_data); - else - goodix_ts_power_on(core_data); + else + goodix_ts_power_on(core_data); + } + + mutex_lock(&goodix_modules.mutex); + if (!list_empty(&goodix_modules.head)) { + list_for_each_entry_safe( + ext_module, next, &goodix_modules.head, list) + { + if (!ext_module->funcs->after_resume) + continue; + + ret = ext_module->funcs->after_resume( + core_data, ext_module); + if (ret == EVT_CANCEL_RESUME) { + mutex_unlock(&goodix_modules.mutex); + ts_info("Canceled by module:%s", + ext_module->name); + goto out; + } } } + mutex_unlock(&goodix_modules.mutex); +out: /* enable irq */ hw_ops->irq_enable(core_data, true); /* open esd */ - goodix_ts_esd_on(core_data); + goodix_ts_blocking_notify(NOTIFY_RESUME, NULL); ts_info("Resume end"); return 0; } @@ -2460,6 +2804,37 @@ static int goodix_ts_pm_resume(struct device *dev) #endif #endif +/** + * goodix_generic_noti_callback - generic notifier callback + * for goodix touch notification event. + */ +static int goodix_generic_noti_callback( + struct notifier_block *self, unsigned long action, void *data) +{ + struct goodix_ts_core *cd = + container_of(self, struct goodix_ts_core, ts_notifier); + const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; + + if (cd->init_stage < CORE_INIT_STAGE2) + return 0; + + ts_info("notify event type 0x%x", (unsigned int)action); + switch (action) { + case NOTIFY_FWUPDATE_START: + hw_ops->irq_enable(cd, 0); + break; + case NOTIFY_FWUPDATE_SUCCESS: + case NOTIFY_FWUPDATE_FAILED: + if (hw_ops->read_version(cd, &cd->fw_version)) + ts_info("failed read fw version info[ignore]"); + hw_ops->irq_enable(cd, 1); + break; + default: + break; + } + return 0; +} + int goodix_ts_stage2_init(struct goodix_ts_core *cd) { int ret; @@ -2491,7 +2866,7 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) ts_err("failed set pen device"); goto err_finger; } - mutex_init(&cd->ble_data.lock); + mutex_init(&goodix_ble_data.lock); } #if IS_ENABLED(CONFIG_FB) @@ -2603,7 +2978,7 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) #if IS_ENABLED(CONFIG_GOODIX_GESTURE) /* gesture init */ - ret = gesture_module_init(cd); + ret = gesture_module_init(); if (ret < 0) { ts_err("failed set init gesture"); goto err_init_gesture; @@ -2611,18 +2986,12 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) #endif /* inspect init */ - ret = inspect_module_init(cd); + ret = inspect_module_init(); if (ret < 0) { ts_err("failed set init inspect"); goto err_init_inspect; } -/* - * [GOOG] - * Touch frame package will read into `struct goodix_rx_package`. - * The total read size for SPI is `touch_frame_size` + 8 bytes(SPI prefix header). - * Therefore, `touch_frame_package` will need to allocate 8 extra bytes for SPI I/O. - */ cd->touch_frame_size = touch_frame_size; cd->touch_frame_package = devm_kzalloc(&cd->pdev->dev, touch_frame_size + 8, GFP_KERNEL); @@ -2658,7 +3027,6 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) ret = -ENOMEM; goto err_setup_irq; } -/*~[GOOG]*/ /* request irq line */ ret = goodix_ts_irq_setup(cd); @@ -2671,10 +3039,10 @@ int goodix_ts_stage2_init(struct goodix_ts_core *cd) return 0; err_setup_irq: - inspect_module_exit(cd); + inspect_module_exit(); err_init_inspect: #if IS_ENABLED(CONFIG_GOODIX_GESTURE) - gesture_module_exit(cd); + gesture_module_exit(); err_init_gesture: #endif goodix_ts_esd_uninit(cd); @@ -2752,16 +3120,10 @@ static int goodix_later_init_thread(void *data) if (ret < 0) { ts_err("failed to get version info, try to upgrade"); update_flag |= UPDATE_MODE_FORCE; + goto upgrade; } - /* step 2: read ic info */ - ret = hw_ops->get_ic_info(cd, &cd->ic_info); - if (ret < 0) { - ts_err("failed to get ic info, try to upgrade"); - update_flag |= UPDATE_MODE_FORCE; - } - - /* step 3: get config data from config bin */ + /* step 2: get config data from config bin */ ret = goodix_get_config_proc(cd); if (ret < 0) ts_info("no valid ic config found"); @@ -2770,20 +3132,35 @@ static int goodix_later_init_thread(void *data) else ts_info("one binary, no need find config"); - /* step 4: init fw struct add try do fw upgrade */ +upgrade: + /* step 3: init fw struct add try do fw upgrade */ ret = goodix_fw_update_init(cd); if (ret) { ts_err("failed init fw update module"); goto err_out; } - /* step 5: do upgrade */ ts_info("update flag: 0x%X", update_flag); - ret = goodix_do_fw_update(cd, update_flag); + ret = goodix_do_fw_update( + cd->ic_configs[CONFIG_TYPE_NORMAL], update_flag); if (ret) ts_err("failed do fw update"); - print_ic_info(&cd->ic_info); + /* step 4: get fw version and ic_info + * at this step we believe that the ic is in normal mode, + * if the version info is invalid there must have some + * problem we cann't cover so exit init directly. + */ + ret = hw_ops->read_version(cd, &cd->fw_version); + if (ret) { + ts_err("invalid fw version, abort"); + goto uninit_fw; + } + ret = hw_ops->get_ic_info(cd, &cd->ic_info); + if (ret) { + ts_err("invalid ic info, abort"); + goto uninit_fw; + } /* the recommend way to update ic config is throuth ISP, * if not we will send config with interactive mode @@ -2801,7 +3178,7 @@ static int goodix_later_init_thread(void *data) return 0; uninit_fw: - goodix_fw_update_uninit(cd); + goodix_fw_update_uninit(); err_out: ts_err("stage2 init failed"); cd->init_stage = CORE_INIT_FAIL; @@ -2843,16 +3220,25 @@ static int goodix_start_later_init(struct goodix_ts_core *ts_core) */ static int goodix_ts_probe(struct platform_device *pdev) { - struct goodix_device_resource *dev_res = - container_of(pdev, struct goodix_device_resource, pdev); - struct goodix_ts_core *core_data; + struct goodix_ts_core *core_data = NULL; struct goodix_bus_interface *bus_interface; int ret; ts_info("IN"); - core_data = &dev_res->core_data; - bus_interface = &dev_res->bus; + bus_interface = pdev->dev.platform_data; + if (!bus_interface) { + ts_err("Invalid touch device"); + core_module_prob_sate = CORE_MODULE_PROB_FAILED; + return -ENODEV; + } + + core_data = devm_kzalloc( + &pdev->dev, sizeof(struct goodix_ts_core), GFP_KERNEL); + if (!core_data) { + core_module_prob_sate = CORE_MODULE_PROB_FAILED; + return -ENOMEM; + } if (IS_ENABLED(CONFIG_OF) && bus_interface->dev->of_node) { /* parse devicetree property */ @@ -2870,10 +3256,11 @@ static int goodix_ts_probe(struct platform_device *pdev) core_data->hw_ops = goodix_get_hw_ops(); if (!core_data->hw_ops) { ts_err("hw ops is NULL"); + core_module_prob_sate = CORE_MODULE_PROB_FAILED; return -EINVAL; } mutex_init(&core_data->cmd_lock); - + goodix_core_module_init(); /* touch core layer is a platform driver */ core_data->pdev = pdev; core_data->bus = bus_interface; @@ -2911,8 +3298,12 @@ static int goodix_ts_probe(struct platform_device *pdev) goto err_setup_gpio; } + /* generic notifier callback */ + core_data->ts_notifier.notifier_call = goodix_generic_noti_callback; + goodix_ts_register_notifier(&core_data->ts_notifier); + /* debug node init */ - ret = goodix_tools_init(core_data); + ret = goodix_tools_init(); if (ret) { ts_err("failed init tools"); goto err_init_tools; @@ -2922,6 +3313,8 @@ static int goodix_ts_probe(struct platform_device *pdev) // 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; /* Try start a thread to get config-bin info */ ret = goodix_start_later_init(core_data); @@ -2934,14 +3327,16 @@ static int goodix_ts_probe(struct platform_device *pdev) return 0; err_start_late_init: - goodix_tools_exit(core_data); + goodix_tools_exit(); err_init_tools: + goodix_ts_unregister_notifier(&core_data->ts_notifier); goodix_ts_power_off(core_data); err_setup_gpio: goodix_set_pinctrl_state(core_data, PINCTRL_MODE_SUSPEND); err_out: mutex_destroy(&core_data->cmd_lock); core_data->init_stage = CORE_INIT_FAIL; + core_module_prob_sate = CORE_MODULE_PROB_FAILED; ts_err("goodix_ts_core failed, ret:%d", ret); return ret; } @@ -2950,45 +3345,38 @@ static int goodix_ts_remove(struct platform_device *pdev) { struct goodix_ts_core *core_data = platform_get_drvdata(pdev); struct goodix_ts_hw_ops *hw_ops = core_data->hw_ops; - struct goodix_ts_esd *ts_esd = &core_data->ts_esd; - if (core_data->init_stage >= CORE_INIT_STAGE2) { -/* [GOOG] - * Follow the reversed order of probe() to release resources. - */ hw_ops->irq_enable(core_data, false); - - /* goodix_ts_stage2_init() */ - inspect_module_exit(core_data); + inspect_module_exit(); #if IS_ENABLED(CONFIG_GOODIX_GESTURE) - gesture_module_exit(core_data); + gesture_module_exit(); #endif - if (atomic_read(&ts_esd->esd_on)) - goodix_ts_esd_off(core_data); + core_module_prob_sate = CORE_MODULE_REMOVED; + goodix_ts_esd_uninit(core_data); goodix_ts_procfs_exit(core_data); + #if IS_ENABLED(CONFIG_GOOG_TOUCH_INTERFACE) #if IS_ENABLED(CONFIG_GTI_PM) goog_pm_unregister_notification(core_data->gti); #endif - goog_touch_interface_remove(core_data->gti); destroy_workqueue(core_data->event_wq); touch_apis_deinit(&core_data->pdev->dev); -#endif + goog_touch_interface_remove(core_data->gti); goodix_ts_sysfs_exit(core_data); +#endif #if IS_ENABLED(CONFIG_FB) fb_unregister_client(&core_data->fb_notifier); #endif goodix_ts_pen_dev_remove(core_data); goodix_ts_input_dev_remove(core_data); - /* goodix_later_init_thread() */ - goodix_fw_update_uninit(core_data); + + goodix_fw_update_uninit(); } - /* goodix_ts_probe() */ - goodix_tools_exit(core_data); + goodix_tools_exit(); + goodix_ts_unregister_notifier(&core_data->ts_notifier); goodix_ts_power_off(core_data); -/*~[GOOG] */ goodix_set_pinctrl_state(core_data, PINCTRL_MODE_SUSPEND); mutex_destroy(&core_data->cmd_lock); @@ -3028,23 +3416,15 @@ static int __init goodix_ts_core_init(void) int ret; ts_info("Core layer init:%s", GOODIX_DRIVER_VERSION); - goodix_device_manager_init(); - #ifdef CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI ret = goodix_spi_bus_init(); - if (ret) { - ts_err("failed add spi bus driver"); - return ret; - } -#endif -#ifdef CONFIG_TOUCHSCREEN_GOODIX_BRL_I2C +#else ret = goodix_i2c_bus_init(); +#endif if (ret) { - ts_err("failed add i2c bus driver"); + ts_err("failed add bus driver"); return ret; } -#endif - return platform_driver_register(&goodix_ts_driver); } @@ -3054,11 +3434,9 @@ static void __exit goodix_ts_core_exit(void) platform_driver_unregister(&goodix_ts_driver); #ifdef CONFIG_TOUCHSCREEN_GOODIX_BRL_SPI goodix_spi_bus_exit(); -#endif -#ifdef CONFIG_TOUCHSCREEN_GOODIX_BRL_I2C +#else goodix_i2c_bus_exit(); #endif - goodix_device_manager_exit(); } late_initcall(goodix_ts_core_init); diff --git a/goodix_ts_core.h b/goodix_ts_core.h index bb03a78..33a59ee 100644 --- a/goodix_ts_core.h +++ b/goodix_ts_core.h @@ -16,22 +16,21 @@ */ #ifndef _GOODIX_TS_CORE_H_ #define _GOODIX_TS_CORE_H_ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/firmware.h> -#include <linux/slab.h> #include <asm/unaligned.h> -#include <linux/vmalloc.h> -#include <linux/kthread.h> +#include <linux/completion.h> #include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/platform_device.h> -#include <linux/miscdevice.h> +#include <linux/firmware.h> +#include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/completion.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/mutex.h> #include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> #include <drm/drm_panel.h> #if IS_ENABLED(CONFIG_OF) #include <linux/of_gpio.h> @@ -57,7 +56,7 @@ #define GOODIX_CORE_DRIVER_NAME "goodix_ts" #define GOODIX_PEN_DRIVER_NAME "goodix_ts,pen" -#define GOODIX_DRIVER_VERSION "v1.2.5" +#define GOODIX_DRIVER_VERSION "v1.2.4" #define GOODIX_MAX_TOUCH 10 #define GOODIX_PEN_MAX_PRESSURE 4096 #define GOODIX_MAX_PEN_KEY 2 @@ -75,18 +74,11 @@ #define GOODIX_RETRY_5 5 #define GOODIX_RETRY_10 10 -/* - * [GOOG] - * Don't hardcode for tx/rx num. -#define GOODIX_MAX_DRV_NUM 32 -#define GOODIX_MAX_SEN_NUM 39 - */ #define GOODIX_GESTURE_UNKNOWN 0x00 #define GOODIX_GESTURE_DOUBLE_TAP 0xCC #define GOODIX_GESTURE_SINGLE_TAP 0x4C #define GOODIX_GESTURE_FOD_DOWN 0x46 #define GOODIX_GESTURE_FOD_UP 0x55 -/*~[GOOG] */ #define TS_DEFAULT_FIRMWARE "goodix_firmware.bin" #define TS_DEFAULT_CFG_BIN "goodix_cfg_group.bin" @@ -473,45 +465,6 @@ enum touch_point_status { TS_RELEASE, TS_TOUCH, }; - -enum update_status { - UPSTA_NOTWORK = 0, - UPSTA_PREPARING, - UPSTA_UPDATING, - UPSTA_SUCCESS, - UPSTA_FAILED -}; - -struct fw_subsys_info { - u8 type; - u32 size; - u32 flash_addr; - const u8 *data; -}; - -#pragma pack(1) -struct firmware_summary { - u32 size; - u32 checksum; - u8 hw_pid[6]; - u8 hw_vid[3]; - u8 fw_pid[8]; - u8 fw_vid[4]; - u8 subsys_num; - u8 chip_type; - u8 protocol_ver; - u8 bus_type; - u8 flash_protect; - // u8 reserved[8]; - struct fw_subsys_info subsys[47]; -}; -#pragma pack() - -struct firmware_data { - struct firmware_summary fw_summary; - const struct firmware *firmware; -}; - /* coordinate package */ struct goodix_ts_coords { int status; /* NONE, RELEASE, TOUCH */ @@ -545,24 +498,6 @@ struct goodix_ts_key { int code; }; -#define GOODIX_MAX_PEN_FREQ_DATA_LEN 16 -#define GOODIX_HOGP_INFO_LEN 3 - -#pragma pack(1) -struct goodix_hid_hogp { - u16 pressure; - u8 key; -}; -#pragma pack() - -struct goodix_ble_data { - u8 freq[GOODIX_MAX_PEN_FREQ_DATA_LEN]; - u8 hogp[GOODIX_HOGP_INFO_LEN]; - int hogp_ready; - int freq_ready; - struct mutex lock; -}; - struct goodix_pen_data { struct goodix_pen_coords coords; struct goodix_ts_key keys[GOODIX_MAX_PEN_KEY]; @@ -678,7 +613,7 @@ struct goodix_self_sensing_data { }; struct goodix_rx_package { - uint8_t header[8]; /* SPI prefix */ + uint8_t header[8]; uint16_t data[0]; }; @@ -769,6 +704,7 @@ struct goodix_ts_esd { bool skip_once; atomic_t esd_on; struct delayed_work esd_work; + struct notifier_block esd_notifier; struct goodix_ts_core *ts_core; }; @@ -784,77 +720,36 @@ struct goodix_ic_config { u8 data[GOODIX_CFG_MAX_SIZE]; }; -struct fw_update_ctrl { - struct mutex mutex; - int initialized; - char fw_name[GOODIX_MAX_STR_LABEL_LEN]; - int mode; - enum update_status status; - int spend_time; - - struct firmware_data fw_data; - struct goodix_ic_config *ic_config; - struct goodix_ic_config one_binary_cfg; - struct goodix_ts_core *core_data; - struct update_info_t *update_info; - struct kobject *kobj; - struct attribute_group attrs; /* [GOOG] */ -}; - -struct goodix_tools_dev { - bool is_open; - struct miscdevice miscdev; - char name[32]; -}; - struct goodix_ts_core { int init_stage; - struct goodix_tools_dev tools_dev; - struct fw_update_ctrl update_ctrl; - struct kobject *gesture_kobj; - struct proc_dir_entry *proc_dir_entry; struct platform_device *pdev; struct goodix_fw_version fw_version; struct goodix_ic_info ic_info; struct goodix_bus_interface *bus; struct goodix_ts_board_data board_data; + struct touch_apis_data apis_data; struct goodix_ts_hw_ops *hw_ops; struct input_dev *input_dev; struct input_dev *pen_dev; struct mutex cmd_lock; /* TODO counld we remove this from core data? */ struct goodix_ts_event ts_event; - struct goodix_ble_data ble_data; - u32 pen_pressure; - - char input_name[32]; - char input_pen_name[32]; + struct workqueue_struct *event_wq; + struct delayed_work monitor_gesture_work; + ktime_t gesture_down_timeout; + ktime_t gesture_up_timeout; /* every pointer of this array represent a kind of config */ struct goodix_ic_config *ic_configs[GOODIX_MAX_CONFIG_GROUP]; struct regulator *avdd; struct regulator *iovdd; - uint32_t gesture_type; - - /* - * [GOOG] - * Use goodix_update_heatmap() to do the heatmap process. - u8 heatmap_buffer; - s16 heatmap_diff[GOODIX_MAX_DRV_NUM * GOODIX_MAX_SEN_NUM]; - s16 heatmap_selfdiff[GOODIX_MAX_DRV_NUM + GOODIX_MAX_SEN_NUM]; - */ - struct touch_apis_data apis_data; - struct workqueue_struct *event_wq; - struct delayed_work monitor_gesture_work; - ktime_t gesture_down_timeout; - ktime_t gesture_up_timeout; + unsigned char gesture_type; struct goodix_rx_package *touch_frame_package; size_t touch_frame_size; uint16_t *mutual_data; uint16_t *self_sensing_data; uint16_t *mutual_data_manual; uint16_t *self_sensing_data_manual; - /*~[GOOG] */ int power_on; int irq; @@ -862,17 +757,16 @@ struct goodix_ts_core { atomic_t irq_enabled; atomic_t suspended; - bool screen_protector_mode_enabled; /* [GOOG] */ + bool screen_protector_mode_enabled; /* when this flag is true, driver should not clean the sync flag */ bool tools_ctrl_sync; + struct notifier_block ts_notifier; struct goodix_ts_esd ts_esd; #if IS_ENABLED(CONFIG_FB) struct notifier_block fb_notifier; #endif - - /* [GOOG] */ #if IS_ENABLED(CONFIG_TOUCHSCREEN_MOTION_FILTER) struct touch_mf tmf; #endif @@ -885,28 +779,93 @@ struct goodix_ts_core { */ ktime_t isr_timestamp; ktime_t coords_timestamp; - /*~[GOOG] */ }; -struct goodix_device_manager { - struct list_head list; - bool initialized; - struct mutex mutex; - int nums; +/* external module structures */ +enum goodix_ext_priority { + EXTMOD_PRIO_RESERVED = 0, + EXTMOD_PRIO_FWUPDATE, + EXTMOD_PRIO_GESTURE, + EXTMOD_PRIO_HOTKNOT, + EXTMOD_PRIO_DBGTOOL, + EXTMOD_PRIO_DEFAULT, +}; + +#define EVT_HANDLED 0 +#define EVT_CONTINUE 0 +#define EVT_CANCEL 1 +#define EVT_CANCEL_IRQEVT 1 +#define EVT_CANCEL_SUSPEND 1 +#define EVT_CANCEL_RESUME 1 +#define EVT_CANCEL_RESET 1 + +struct goodix_ext_module; +/* external module's operations callback */ +struct goodix_ext_module_funcs { + int (*init)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*exit)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*before_reset)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*after_reset)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*before_suspend)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*after_suspend)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*before_resume)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*after_resume)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); + int (*irq_event)(struct goodix_ts_core *core_data, + struct goodix_ext_module *module); }; -struct goodix_device_resource { +/* + * struct goodix_ext_module - external module struct + * @list: list used to link into modules manager + * @name: name of external module + * @priority: module priority value, zero is invalid + * @funcs: operations callback + * @priv_data: private data region + * @kobj: kobject + * @work: used to queue one work to do registration + */ +struct goodix_ext_module { struct list_head list; - int id; - char name[64]; - struct goodix_bus_interface bus; - struct platform_device pdev; - struct goodix_ts_core core_data; + char *name; + enum goodix_ext_priority priority; + const struct goodix_ext_module_funcs *funcs; + void *priv_data; + struct kobject kobj; + struct work_struct work; }; -extern struct goodix_device_manager goodix_devices; -extern int goodix_device_register(struct goodix_device_resource *device); +/* + * struct goodix_ext_attribute - exteranl attribute struct + * @attr: attribute + * @show: show interface of external attribute + * @store: store interface of external attribute + */ +struct goodix_ext_attribute { + struct attribute attr; + 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 */ +#define __EXTMOD_ATTR(_name, _mode, _show, _store) \ + { \ + .attr = { .name = __stringify(_name), .mode = _mode }, \ + .show = _show, .store = _store, \ + } + +/* 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) /* log macro */ extern bool debug_log_flag; @@ -932,6 +891,31 @@ static inline struct goodix_ts_board_data *board_data( return &(core->board_data); } +/** + * goodix_register_ext_module - interface for external module + * to register into touch core modules structure + * + * @module: pointer to external module to be register + * return: 0 ok, <0 failed + */ +int goodix_register_ext_module(struct goodix_ext_module *module); +/* register module no wait */ +int goodix_register_ext_module_no_wait(struct goodix_ext_module *module); +/** + * goodix_unregister_ext_module - interface for external module + * to unregister external modules + * + * @module: pointer to external module + * return: 0 ok, <0 failed + */ +int goodix_unregister_ext_module(struct goodix_ext_module *module); +/* remove all registered ext module + * return 0 on success, otherwise return < 0 + */ +int goodix_ts_blocking_notify(enum ts_notify_event evt, void *v); +struct kobj_type *goodix_get_default_ktype(void); +struct kobject *goodix_get_default_kobj(void); + struct goodix_ts_hw_ops *goodix_get_hw_ops(void); int goodix_get_config_proc(struct goodix_ts_core *cd); @@ -947,26 +931,22 @@ u32 goodix_get_file_config_id(u8 *ic_config); void goodix_rotate_abcd2cbad(int tx, int rx, s16 *src, s16 *dest); int goodix_fw_update_init(struct goodix_ts_core *core_data); -void goodix_fw_update_uninit(struct goodix_ts_core *core_data); -int goodix_do_fw_update(struct goodix_ts_core *core_data, int mode); +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, struct goodix_bus_interface *bus_inf); -int gesture_module_init(struct goodix_ts_core *core_data); -void gesture_module_exit(struct goodix_ts_core *core_data); -int inspect_module_init(struct goodix_ts_core *core_data); -void inspect_module_exit(struct goodix_ts_core *core_data); -int goodix_tools_init(struct goodix_ts_core *core_data); -void goodix_tools_exit(struct goodix_ts_core *core_data); -void goodix_ts_esd_on(struct goodix_ts_core *cd); -void goodix_ts_esd_off(struct goodix_ts_core *cd); -void print_ic_info(struct goodix_ic_info *ic_info); - -int driver_test_selftest(struct goodix_ts_core *cd, char *buf); +int gesture_module_init(void); +void gesture_module_exit(void); +int inspect_module_init(void); +void inspect_module_exit(void); +int goodix_tools_init(void); +void goodix_tools_exit(void); + +int driver_test_selftest(char* buf); int driver_test_proc_init(struct goodix_ts_core *core_data); -void driver_test_proc_remove(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); -int goodix_ts_report_gesture(struct goodix_ts_core *cd, struct goodix_ts_event *event); void goodix_ts_report_status(struct goodix_ts_core *core_data, struct goodix_ts_event *ts_event); int goodix_update_pen_freq(struct goodix_ts_core *cd, u8 *data, int len); diff --git a/goodix_ts_gesture.c b/goodix_ts_gesture.c index 51335da..d4246b0 100644 --- a/goodix_ts_gesture.c +++ b/goodix_ts_gesture.c @@ -27,136 +27,236 @@ #include <linux/spinlock.h> #include <linux/string.h> #include <linux/version.h> + /* - * [GOOG] - * Move GOODIX_GESTURE_* define to goodix_ts_core.h. + * struct gesture_module - gesture module data + * @registered: module register state + * @sysfs_node_created: sysfs node state + * @gesture_type: valid gesture type, each bit represent one gesture type + * @gesture_data: store latest gesture code get from irq event + * @gesture_ts_cmd: gesture command data */ +struct gesture_module { + atomic_t registered; + 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; -static ssize_t gsx_double_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t gsx_double_type_show(struct goodix_ext_module *module, char *buf) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); - uint32_t type = cd->gesture_type; + 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_DOUBLE_TAP) ? "enable" : "disable"); } -static ssize_t gsx_double_type_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gsx_double_type_store( + struct goodix_ext_module *module, const char *buf, size_t count) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); + struct gesture_module *gsx = module->priv_data; + + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; + } if (buf[0] == '1') { ts_info("enable double tap"); - cd->gesture_type |= GESTURE_DOUBLE_TAP; + gsx->ts_core->gesture_type |= GESTURE_DOUBLE_TAP; } else if (buf[0] == '0') { ts_info("disable double tap"); - cd->gesture_type &= ~GESTURE_DOUBLE_TAP; + gsx->ts_core->gesture_type &= ~GESTURE_DOUBLE_TAP; } else ts_err("invalid cmd[%d]", buf[0]); return count; } -static ssize_t gsx_single_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t gsx_single_type_show(struct goodix_ext_module *module, char *buf) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); - uint32_t type = cd->gesture_type; + 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_SINGLE_TAP) ? "enable" : "disable"); } -static ssize_t gsx_single_type_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gsx_single_type_store( + struct goodix_ext_module *module, const char *buf, size_t count) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); + struct gesture_module *gsx = module->priv_data; + + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; + } if (buf[0] == '1') { ts_info("enable single tap"); - cd->gesture_type |= GESTURE_SINGLE_TAP; + gsx->ts_core->gesture_type |= GESTURE_SINGLE_TAP; } else if (buf[0] == '0') { ts_info("disable single tap"); - cd->gesture_type &= ~GESTURE_SINGLE_TAP; + gsx->ts_core->gesture_type &= ~GESTURE_SINGLE_TAP; } else ts_err("invalid cmd[%d]", buf[0]); return count; } -static ssize_t gsx_fod_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t gsx_fod_type_show(struct goodix_ext_module *module, char *buf) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); - uint32_t type = cd->gesture_type; + 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_fod_type_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gsx_fod_type_store( + struct goodix_ext_module *module, const char *buf, size_t count) { - struct device *device = - container_of(((struct kobject *)dev)->parent, struct device, kobj); - struct goodix_ts_core *cd = dev_get_drvdata(device); + struct gesture_module *gsx = module->priv_data; + + if (!gsx) + return -EIO; + + if (atomic_read(&gsx->registered) == 0) { + ts_err("gesture module is not registered"); + return 0; + } if (buf[0] == '1') { ts_info("enable fod"); - cd->gesture_type |= GESTURE_FOD_PRESS; + gsx->ts_core->gesture_type |= GESTURE_FOD_PRESS; } else if (buf[0] == '0') { ts_info("disable fod"); - cd->gesture_type &= ~GESTURE_FOD_PRESS; + gsx->ts_core->gesture_type &= ~GESTURE_FOD_PRESS; } else ts_err("invalid cmd[%d]", buf[0]); return count; } -static DEVICE_ATTR(double_type, 0664, gsx_double_type_show, gsx_double_type_store); -static DEVICE_ATTR(single_type, 0664, gsx_single_type_show, gsx_single_type_store); -static DEVICE_ATTR(fod_type, 0664, gsx_fod_type_show, gsx_fod_type_store); - -static struct attribute *gesture_attrs[] = { - &dev_attr_double_type.attr, - &dev_attr_single_type.attr, - &dev_attr_fod_type.attr, - NULL, +const struct goodix_ext_attribute gesture_attrs[] = { + __EXTMOD_ATTR( + 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), }; -const static struct attribute_group gesture_sysfs_group = { - .attrs = gesture_attrs, -}; +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; + } + + gsx->ts_core = cd; + gsx->ts_core->gesture_type = 0; + atomic_set(&gsx->registered, 1); + + return 0; +} + +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; + } + + atomic_set(&gsx->registered, 0); + + return 0; +} -int goodix_ts_report_gesture(struct goodix_ts_core *cd, struct goodix_ts_event *event) +/** + * gsx_gesture_ist - Gesture Irq handle + * This functions is excuted when interrupt happened and + * ic in doze mode. + * + * @cd: pointer to touch core data + * @module: pointer to goodix_ext_module struct + * return: 0 goon execute, EVT_CANCEL_IRQEVT stop execute + */ +static int gsx_gesture_ist( + struct goodix_ts_core *cd, struct goodix_ext_module *module) { + struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; + struct goodix_ts_event gs_event = { 0 }; int coor_x, coor_y, coor_size, coor_press; int major, minor, orientation; + int ret; + + if (atomic_read(&cd->suspended) == 0 || cd->gesture_type == 0) + return EVT_CONTINUE; + + ret = hw_ops->event_handler(cd, &gs_event); + if (ret) { + ts_err("failed get gesture data"); + cd->hw_ops->gesture(cd, 0); + goto re_send_ges_cmd; + } + + if (!(gs_event.event_type & EVENT_GESTURE)) { + ts_err("invalid event type: 0x%x", cd->ts_event.event_type); + cd->hw_ops->gesture(cd, 0); + goto re_send_ges_cmd; + } + + if (gs_event.event_type & EVENT_STATUS) + goodix_ts_report_status(cd, &gs_event); - coor_x = le16_to_cpup((__le16 *)event->gesture_data.data); - coor_y = le16_to_cpup((__le16 *)(event->gesture_data.data + 2)); - coor_size = le16_to_cpup((__le16 *)(event->gesture_data.data + 4)); - coor_press = event->gesture_data.data[6]; - major = le16_to_cpup((__le16 *)(event->gesture_data.data + 7)); - minor = le16_to_cpup((__le16 *)(event->gesture_data.data + 9)); - orientation = (s8)event->gesture_data.data[11]; + coor_x = le16_to_cpup((__le16 *)gs_event.gesture_data.data); + coor_y = le16_to_cpup((__le16 *)(gs_event.gesture_data.data + 2)); + coor_size = le16_to_cpup((__le16 *)(gs_event.gesture_data.data + 4)); + coor_press = gs_event.gesture_data.data[6]; + major = le16_to_cpup((__le16 *)(gs_event.gesture_data.data + 7)); + minor = le16_to_cpup((__le16 *)(gs_event.gesture_data.data + 9)); + orientation = (s8)gs_event.gesture_data.data[11]; - switch (event->gesture_data.gesture_type) { + switch (gs_event.gesture_data.gesture_type) { case GOODIX_GESTURE_SINGLE_TAP: if (cd->gesture_type & GESTURE_SINGLE_TAP) { ts_info("get SINGLE-TAP gesture"); @@ -240,45 +340,132 @@ int goodix_ts_report_gesture(struct goodix_ts_core *cd, struct goodix_ts_event * } break; default: - ts_err("not support gesture type[%02X]", event->gesture_data.gesture_type); + ts_err("not support gesture type[%02X]", gs_event.gesture_data.gesture_type); break; } - return 0; +re_send_ges_cmd: + return EVT_CANCEL_IRQEVT; } -int gesture_module_init(struct goodix_ts_core *core_data) +/** + * gsx_gesture_before_suspend - execute gesture suspend routine + * This functions is excuted to set ic into doze mode + * + * @cd: pointer to touch core data + * @module: pointer to goodix_ext_module struct + * return: 0 goon execute, EVT_IRQCANCLED stop execute + */ +static int gsx_gesture_before_suspend( + struct goodix_ts_core *cd, struct goodix_ext_module *module) { - int ret = 0; - struct kobject *parent = &core_data->pdev->dev.kobj; + 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, type[0x%02X]", cd->gesture_type); + + hw_ops->irq_enable(cd, true); + enable_irq_wake(cd->irq); + + return EVT_CANCEL_SUSPEND; +} + +static int gsx_gesture_before_resume( + struct goodix_ts_core *cd, struct goodix_ext_module *module) +{ + const struct goodix_ts_hw_ops *hw_ops = cd->hw_ops; + + if (cd->gesture_type == 0) + return EVT_CONTINUE; + + disable_irq_wake(cd->irq); + hw_ops->reset(cd, GOODIX_NORMAL_RESET_DELAY_MS); + + return EVT_CANCEL_RESUME; +} + +static struct goodix_ext_module_funcs gsx_gesture_funcs = { + .irq_event = gsx_gesture_ist, + .init = gsx_gesture_init, + .exit = gsx_gesture_exit, + .before_suspend = gsx_gesture_before_suspend, + .before_resume = gsx_gesture_before_resume, +}; + +int gesture_module_init(void) +{ + int ret; + int i; + struct kobject *def_kobj = goodix_get_default_kobj(); + struct kobj_type *def_kobj_type = goodix_get_default_ktype(); + + gsx_gesture = kzalloc(sizeof(struct gesture_module), GFP_KERNEL); + if (!gsx_gesture) + return -ENOMEM; + + gsx_gesture->module.funcs = &gsx_gesture_funcs; + gsx_gesture->module.priority = EXTMOD_PRIO_GESTURE; + gsx_gesture->module.name = "Goodix_gsx_gesture"; + gsx_gesture->module.priv_data = gsx_gesture; + + atomic_set(&gsx_gesture->registered, 0); /* gesture sysfs init */ - core_data->gesture_kobj = kobject_create_and_add("gesture", parent); - if (!core_data->gesture_kobj) { + ret = kobject_init_and_add( + &gsx_gesture->module.kobj, def_kobj_type, def_kobj, "gesture"); + if (ret) { ts_err("failed create gesture sysfs node!"); - ret = -ENOENT; /* [GOOG] */ goto err_out; } - ret = sysfs_create_group(core_data->gesture_kobj, &gesture_sysfs_group); + for (i = 0; i < ARRAY_SIZE(gesture_attrs) && !ret; i++) + ret = sysfs_create_file( + &gsx_gesture->module.kobj, &gesture_attrs[i].attr); if (ret) { - ts_err("failed create gesture sysfs files"); - kobject_put(core_data->gesture_kobj); + ts_err("failed create gst sysfs files"); + while (--i >= 0) + sysfs_remove_file(&gsx_gesture->module.kobj, + &gesture_attrs[i].attr); + + kobject_put(&gsx_gesture->module.kobj); goto err_out; } + module_initialized = true; + goodix_register_ext_module_no_wait(&gsx_gesture->module); ts_info("gesture module init success"); + return 0; err_out: ts_err("gesture module init failed!"); + kfree(gsx_gesture); return ret; } -void gesture_module_exit(struct goodix_ts_core *core_data) +void gesture_module_exit(void) { + int i; + ts_info("gesture module exit"); + if (!module_initialized) + return; + + goodix_unregister_ext_module(&gsx_gesture->module); + + /* deinit sysfs */ + for (i = 0; i < ARRAY_SIZE(gesture_attrs); i++) + sysfs_remove_file( + &gsx_gesture->module.kobj, &gesture_attrs[i].attr); - sysfs_remove_group(core_data->gesture_kobj, &gesture_sysfs_group); - kobject_put(core_data->gesture_kobj); + kobject_put(&gsx_gesture->module.kobj); + kfree(gsx_gesture); + module_initialized = false; } diff --git a/goodix_ts_inspect.c b/goodix_ts_inspect.c index bebc557..119c8bc 100644 --- a/goodix_ts_inspect.c +++ b/goodix_ts_inspect.c @@ -122,6 +122,8 @@ #define ABS(val) ((val < 0) ? -(val) : val) #define MAX(a, b) ((a > b) ? a : b) +static bool module_initialized; + /* short threshold, drv-drv, drv-sen, sen-sen, drv-gnd, sen-gnd, avdd */ static u8 short_circuit_threshold[] = { 10, 200, 200, 200, 200, 200, 30 }; @@ -515,7 +517,7 @@ static int goodix_tptest_prepare(struct goodix_ts_test *ts_test) /* disable irq */ ts_test_irq_enable(ts_test, false); /* close esd */ - goodix_ts_esd_off(ts_test->ts); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); return 0; } @@ -527,7 +529,7 @@ static void goodix_tptest_finish(struct goodix_ts_test *ts_test) ts_test_reset(ts_test, 100); /* open esd */ - goodix_ts_esd_on(ts_test->ts); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); /* enable irq */ ts_test_irq_enable(ts_test, true); } @@ -1351,10 +1353,10 @@ static ssize_t get_rawdata_show( static DEVICE_ATTR(get_rawdata, 0444, get_rawdata_show, NULL); -int inspect_module_init(struct goodix_ts_core *core_data) +int inspect_module_init(void) { int ret; - struct kobject *def_kobj = &core_data->pdev->dev.kobj; + struct kobject *def_kobj = goodix_get_default_kobj(); /* create sysfs */ ret = sysfs_create_file(def_kobj, &dev_attr_get_rawdata.attr); @@ -1362,6 +1364,8 @@ int inspect_module_init(struct goodix_ts_core *core_data) ts_err("create sysfs of get_rawdata failed"); goto err_out; } + + module_initialized = true; ts_info("inspect module init success"); return 0; @@ -1370,10 +1374,14 @@ err_out: return ret; } -void inspect_module_exit(struct goodix_ts_core *core_data) +void inspect_module_exit(void) { - struct kobject *def_kobj = &core_data->pdev->dev.kobj; + 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 index d2f0082..a8ed02f 100644 --- a/goodix_ts_proc.c +++ b/goodix_ts_proc.c @@ -52,7 +52,7 @@ #define CMD_SET_FREQ_INDEX "set_freq_index" #define CMD_DISABLE_FILTER "disable_filter" -const static char *cmd_list[] = { CMD_FW_UPDATE, CMD_AUTO_TEST, CMD_OPEN_TEST, +char *cmd_list[] = { CMD_FW_UPDATE, CMD_AUTO_TEST, CMD_OPEN_TEST, CMD_SELF_OPEN_TEST, CMD_NOISE_TEST, CMD_AUTO_NOISE_TEST, CMD_SHORT_TEST, CMD_GET_PACKAGE_ID, CMD_GET_MCU_ID, CMD_GET_VERSION, CMD_GET_RAWDATA, CMD_GET_DIFFDATA, CMD_GET_BASEDATA, CMD_GET_SELF_RAWDATA, @@ -90,6 +90,7 @@ const static char *cmd_list[] = { CMD_FW_UPDATE, CMD_AUTO_TEST, CMD_OPEN_TEST, #define LARGE_SIZE 5 * 1024 #define MAX_FRAME_CNT 50 #define HUGE_SIZE MAX_FRAME_CNT * 20 * 1024 +static struct goodix_ts_core *cd; static char wbuf[SHORT_SIZE]; static char *rbuf; static uint32_t index; @@ -410,7 +411,7 @@ struct goodix_ts_test { }; static struct goodix_ts_test *ts_test; -static int cal_cha_to_cha_res(struct goodix_ts_core *cd, int v1, int v2) +static int cal_cha_to_cha_res(int v1, int v2) { if (cd->bus->ic_type == IC_TYPE_BERLIN_A) return (v1 - v2) * 63 / v2; @@ -422,7 +423,7 @@ static int cal_cha_to_cha_res(struct goodix_ts_core *cd, int v1, int v2) return (v1 / v2 - 1) * 55 + 45; } -static int cal_cha_to_avdd_res(struct goodix_ts_core *cd, int v1, int v2) +static int cal_cha_to_avdd_res(int v1, int v2) { if (cd->bus->ic_type == IC_TYPE_BERLIN_A) return 64 * (2 * v2 - 25) * 40 / v1 - 40; @@ -434,7 +435,7 @@ static int cal_cha_to_avdd_res(struct goodix_ts_core *cd, int v1, int v2) return 64 * (2 * v2 - 25) * 76 / v1 - 15; } -static int cal_cha_to_gnd_res(struct goodix_ts_core *cd, int v) +static int cal_cha_to_gnd_res(int v) { if (cd->bus->ic_type == IC_TYPE_BERLIN_A) return 64148 / v - 40; @@ -557,7 +558,7 @@ static void goodix_save_short_res(u16 chn1, u16 chn2, int r) } } -static int gdix_check_tx_tx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_num) +static int gdix_check_tx_tx_shortcircut(u8 short_ch_num) { int ret = 0, err = 0; u32 r_threshold = 0, short_r = 0; @@ -614,9 +615,11 @@ static int gdix_check_tx_tx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n if (adc_signal < ts_test->short_threshold) continue; - short_r = (u32)cal_cha_to_cha_res(cd, self_capdata, adc_signal); + short_r = (u32)cal_cha_to_cha_res( + self_capdata, adc_signal); if (short_r < r_threshold) { - master_pin_num = map_die2pin(short_die_num + max_sen_num); + master_pin_num = map_die2pin( + short_die_num + max_sen_num); slave_pin_num = map_die2pin(j + max_sen_num); if (master_pin_num == 0xFF || slave_pin_num == 0xFF) { @@ -646,7 +649,7 @@ static int gdix_check_tx_tx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n return err; } -static int gdix_check_rx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_num) +static int gdix_check_rx_rx_shortcircut(u8 short_ch_num) { int ret = 0, err = 0; u32 r_threshold = 0, short_r = 0; @@ -700,7 +703,8 @@ static int gdix_check_rx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n if (adc_signal < ts_test->short_threshold) continue; - short_r = (u32)cal_cha_to_cha_res(cd, self_capdata, adc_signal); + short_r = (u32)cal_cha_to_cha_res( + self_capdata, adc_signal); if (short_r < r_threshold) { master_pin_num = map_die2pin(short_die_num); slave_pin_num = map_die2pin(j); @@ -732,7 +736,7 @@ static int gdix_check_rx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n return err; } -static int gdix_check_tx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_num) +static int gdix_check_tx_rx_shortcircut(u8 short_ch_num) { int ret = 0, err = 0; u32 r_threshold = 0, short_r = 0; @@ -787,7 +791,8 @@ static int gdix_check_tx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n if (adc_signal < ts_test->short_threshold) continue; - short_r = (u32)cal_cha_to_cha_res(cd, self_capdata, adc_signal); + short_r = (u32)cal_cha_to_cha_res( + self_capdata, adc_signal); if (short_r < r_threshold) { master_pin_num = map_die2pin(short_die_num); slave_pin_num = map_die2pin(j + max_sen_num); @@ -819,7 +824,7 @@ static int gdix_check_tx_rx_shortcircut(struct goodix_ts_core *cd, u8 short_ch_n return err; } -static int gdix_check_resistance_to_gnd(struct goodix_ts_core *cd, u16 adc_signal, u32 pos) +static int gdix_check_resistance_to_gnd(u16 adc_signal, u32 pos) { long r = 0; u16 r_th = 0, avdd_value = 0; @@ -837,10 +842,10 @@ static int gdix_check_resistance_to_gnd(struct goodix_ts_core *cd, u16 adc_signa if (short_type == 0) { /* short to GND */ - r = cal_cha_to_gnd_res(cd, adc_signal); + r = cal_cha_to_gnd_res(adc_signal); } else { /* short to VDD */ - r = cal_cha_to_avdd_res(cd, adc_signal, avdd_value); + r = cal_cha_to_avdd_res(adc_signal, avdd_value); } if (pos < max_drv_num) @@ -869,7 +874,7 @@ static int gdix_check_resistance_to_gnd(struct goodix_ts_core *cd, u16 adc_signa return 0; } -static int gdix_check_gndvdd_shortcircut(struct goodix_ts_core *cd) +static int gdix_check_gndvdd_shortcircut(void) { int ret = 0, err = 0; int size = 0, i = 0; @@ -902,7 +907,7 @@ static int gdix_check_gndvdd_shortcircut(struct goodix_ts_core *cd) for (i = 0; i < max_drv_num + max_sen_num; i++) { adc_signal = le16_to_cpup((__le16 *)&data_buf[i * 2]); - ret = gdix_check_resistance_to_gnd(cd, adc_signal, i); + ret = gdix_check_resistance_to_gnd(adc_signal, i); if (ret != 0) { ts_err("Resistance to-gnd/vdd short"); err = ret; @@ -917,7 +922,7 @@ err_out: #define NOTT_CHECKSUM_LEN 54 #define BRLD_CHECKSUM_LEN 62 #define BRLB_CHECKSUM_LEN 129 -static int goodix_shortcircut_analysis(struct goodix_ts_core *cd) +static int goodix_shortcircut_analysis(void) { int ret; int err = 0; @@ -958,13 +963,13 @@ static int goodix_shortcircut_analysis(struct goodix_ts_core *cd) test_result.drv_gnd_avdd_num, test_result.sen_gnd_avdd_num); if (test_result.drv_drv_num) - err |= gdix_check_tx_tx_shortcircut(cd, test_result.drv_drv_num); + err |= gdix_check_tx_tx_shortcircut(test_result.drv_drv_num); if (test_result.sen_sen_num) - err |= gdix_check_rx_rx_shortcircut(cd, test_result.sen_sen_num); + err |= gdix_check_rx_rx_shortcircut(test_result.sen_sen_num); if (test_result.drv_sen_num) - err |= gdix_check_tx_rx_shortcircut(cd, test_result.drv_sen_num); + err |= gdix_check_tx_rx_shortcircut(test_result.drv_sen_num); if (test_result.drv_gnd_avdd_num || test_result.sen_gnd_avdd_num) - err |= gdix_check_gndvdd_shortcircut(cd); + err |= gdix_check_gndvdd_shortcircut(); ts_info(">>>>> short check return 0x%x", err); @@ -974,7 +979,7 @@ static int goodix_shortcircut_analysis(struct goodix_ts_core *cd) #define INSPECT_FW_SWITCH_CMD 0x85 #define SHORT_TEST_RUN_FLAG 0xAA #define SHORT_TEST_RUN_REG 0x10400 -static int goodix_short_test_prepare(struct goodix_ts_core *cd) +static int goodix_short_test_prepare(void) { struct goodix_ts_cmd tmp_cmd; int ret; @@ -1013,7 +1018,7 @@ resend_cmd: #define MAX_TEST_TIME_MS 15000 #define DEFAULT_TEST_TIME_MS 7000 #define SHORT_TEST_FINISH_FLAG 0x88 -static int goodix_shortcircut_test(struct goodix_ts_core *cd) +static int goodix_shortcircut_test(void) { int ret = 0; int res; @@ -1022,7 +1027,7 @@ static int goodix_shortcircut_test(struct goodix_ts_core *cd) u8 status; ts_info("---------------------- short_test begin ----------------------"); - ret = goodix_short_test_prepare(cd); + ret = goodix_short_test_prepare(); if (ret < 0) { ts_err("Failed enter short test mode"); return ret; @@ -1066,7 +1071,7 @@ static int goodix_shortcircut_test(struct goodix_ts_core *cd) /* start analysis short result */ ts_info("short_test finished, start analysis"); - res = goodix_shortcircut_analysis(cd); + res = goodix_shortcircut_analysis(); if (res == 0) { ts_test->result[GTP_SHORT_TEST] = TEST_OK; ret = 0; @@ -1088,8 +1093,7 @@ typedef struct __attribute__((packed)) { #define FLASH_CMD_STATE_CHECKERR 0x05 #define FLASH_CMD_STATE_DENY 0x06 #define FLASH_CMD_STATE_OKAY 0x07 -static int goodix_flash_cmd(struct goodix_ts_core *cd, - uint8_t cmd, uint8_t status, int retry_count) +static int goodix_flash_cmd(uint8_t cmd, uint8_t status, int retry_count) { u8 cmd_buf[] = { 0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }; int ret; @@ -1118,7 +1122,7 @@ static int goodix_flash_cmd(struct goodix_ts_core *cd, return -EINVAL; } -static int goodix_flash_read(struct goodix_ts_core *cd, u32 addr, u8 *buf, int len) +static int goodix_flash_read(u32 addr, u8 *buf, int len) { int i; int ret; @@ -1138,7 +1142,7 @@ static int goodix_flash_read(struct goodix_ts_core *cd, u32 addr, u8 *buf, int l checksum += p[i] | (p[i + 1] << 8); head_info.checksum = checksum; - ret = goodix_flash_cmd(cd, FLASH_CMD_R_START, FLASH_CMD_STATE_READY, 15); + ret = goodix_flash_cmd(FLASH_CMD_R_START, FLASH_CMD_STATE_READY, 15); if (ret < 0) { ts_err("failed enter flash read state"); goto read_end; @@ -1151,7 +1155,7 @@ static int goodix_flash_read(struct goodix_ts_core *cd, u32 addr, u8 *buf, int l goto read_end; } - ret = goodix_flash_cmd(cd, FLASH_CMD_RW_FINISH, FLASH_CMD_STATE_OKAY, 50); + ret = goodix_flash_cmd(FLASH_CMD_RW_FINISH, FLASH_CMD_STATE_OKAY, 50); if (ret) { ts_err("faild read flash ready state"); goto read_end; @@ -1178,7 +1182,7 @@ static int goodix_flash_read(struct goodix_ts_core *cd, u32 addr, u8 *buf, int l memcpy(buf, tmp_buf + sizeof(flash_head_info_t), len); ret = 0; read_end: - goodix_flash_cmd(cd, 0x0C, 0, 0); + goodix_flash_cmd(0x0C, 0, 0); return ret; } @@ -1219,27 +1223,15 @@ static const struct seq_operations seq_ops = { static int driver_test_open(struct inode *inode, struct file *file) { - struct seq_file *seq_file; - int ret; - - ret = seq_open(file, &seq_ops); - if (ret) - return ret; - seq_file = (struct seq_file *)file->private_data; - if (seq_file) - seq_file->private = PDE_DATA(inode); - - mutex_lock(&goodix_devices.mutex); - return 0; + return seq_open(file, &seq_ops); } static int driver_test_release(struct inode *inode, struct file *file) { - mutex_unlock(&goodix_devices.mutex); return seq_release(inode, file); } -static void goodix_save_header(struct goodix_ts_core *cd) +static void goodix_save_header(void) { int i; bool total_result = true; @@ -1473,7 +1465,7 @@ static void goodix_data_cal(s16 *data, size_t data_size, s16 *stat_result) stat_result[2] = min; } -static void goodix_save_data(struct goodix_ts_core *cd) +static void goodix_save_data(void) { int tx = cd->ic_info.parm.drv_num; int rx = cd->ic_info.parm.sen_num; @@ -1561,12 +1553,12 @@ static void goodix_save_data(struct goodix_ts_core *cd) index += sprintf(&rbuf[index], "</DataRecord>\n"); } -static void goodix_save_tail(struct goodix_ts_core *cd) +static void goodix_save_tail(void) { index += sprintf(&rbuf[index], "</TESTLOG>\n"); } -static void goodix_save_test_result(struct goodix_ts_core *cd, bool is_brief) +static void goodix_save_test_result(bool is_brief) { if (is_brief) { if (ts_test->item[GTP_CAP_TEST]) { @@ -1600,9 +1592,9 @@ static void goodix_save_test_result(struct goodix_ts_core *cd, bool is_brief) : "FAIL"); } } else { - goodix_save_header(cd); - goodix_save_data(cd); - goodix_save_tail(cd); + goodix_save_header(); + goodix_save_data(); + goodix_save_tail(); } } @@ -1732,7 +1724,7 @@ static int parse_csvfile( return parse_valid_data(buf, size, ptr, data, rows); } -static int goodix_obtain_testlimits(struct goodix_ts_core *cd) +static int goodix_obtain_testlimits(void) { const struct firmware *firmware = NULL; struct device *dev = &cd->pdev->dev; @@ -1855,7 +1847,7 @@ exit_free: return ret; } -static int goodix_delta_test(struct goodix_ts_core *cd) +static int goodix_delta_test(void) { int i, j; int max_val; @@ -1907,7 +1899,7 @@ static int goodix_delta_test(struct goodix_ts_core *cd) return ret; } -static int goodix_open_test(struct goodix_ts_core *cd) +static int goodix_open_test(void) { u8 *tmp_buf; struct goodix_ts_cmd temp_cmd; @@ -2007,7 +1999,7 @@ static int goodix_open_test(struct goodix_ts_core *cd) ts_test->result[GTP_CAP_TEST] = TEST_NG; } - if (goodix_delta_test(cd) == 0) + if (goodix_delta_test() == 0) ts_test->result[GTP_DELTA_TEST] = TEST_OK; exit: @@ -2015,7 +2007,7 @@ exit: return ret; } -static int goodix_self_open_test(struct goodix_ts_core *cd) +static int goodix_self_open_test(void) { u8 *tmp_buf; struct goodix_ts_cmd temp_cmd; @@ -2093,7 +2085,7 @@ exit: return ret; } -static int goodix_noise_test(struct goodix_ts_core *cd) +static int goodix_noise_test(void) { u8 *tmp_buf; struct goodix_ts_cmd temp_cmd; @@ -2176,19 +2168,19 @@ exit: return ret; } -static int goodix_auto_test(struct goodix_ts_core *cd, bool is_brief) +static int goodix_auto_test(bool is_brief) { struct goodix_ts_cmd temp_cmd; int ret; - ret = goodix_obtain_testlimits(cd); + ret = goodix_obtain_testlimits(); if (ret < 0) { ts_err("obtain open test limits failed"); return ret; } cd->hw_ops->irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); temp_cmd.len = 5; temp_cmd.cmd = 0x64; @@ -2198,7 +2190,7 @@ static int goodix_auto_test(struct goodix_ts_core *cd, bool is_brief) ret = cd->hw_ops->send_cmd(cd, &temp_cmd); if (ret < 0) ts_err("enter test mode failed"); - goodix_open_test(cd); + goodix_open_test(); cd->hw_ops->reset(cd, 100); } @@ -2206,27 +2198,27 @@ static int goodix_auto_test(struct goodix_ts_core *cd, bool is_brief) ret = cd->hw_ops->send_cmd(cd, &temp_cmd); if (ret < 0) ts_err("enter test mode failed"); - goodix_noise_test(cd); + goodix_noise_test(); cd->hw_ops->reset(cd, 100); } if (ts_test->item[GTP_SELFCAP_TEST]) { - goodix_self_open_test(cd); + goodix_self_open_test(); cd->hw_ops->reset(cd, 100); } if (ts_test->item[GTP_SHORT_TEST]) { - goodix_shortcircut_test(cd); + goodix_shortcircut_test(); cd->hw_ops->reset(cd, 100); } cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); - goodix_save_test_result(cd, is_brief); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + goodix_save_test_result(is_brief); return 0; } -static void goodix_auto_noise_test(struct goodix_ts_core *cd, u16 cnt, int threshold) +static void goodix_auto_noise_test(u16 cnt, int threshold) { struct goodix_ts_cmd temp_cmd; struct goodix_ts_cmd rb_cmd; @@ -2253,7 +2245,7 @@ static void goodix_auto_noise_test(struct goodix_ts_core *cd, u16 cnt, int thres 8; cd->hw_ops->irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); restart: temp_cmd.len = 0x07; @@ -2333,10 +2325,10 @@ exit: } kfree(tmp_buf); cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); } -static int get_cap_data(struct goodix_ts_core *cd, uint8_t *type) +static int get_cap_data(uint8_t *type) { struct goodix_ts_cmd temp_cmd; int tx = cd->ic_info.parm.drv_num; @@ -2370,7 +2362,7 @@ static int get_cap_data(struct goodix_ts_core *cd, uint8_t *type) /* disable irq & close esd */ cd->hw_ops->irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); if (strstr(type, CMD_GET_BASEDATA) || strstr(type, CMD_GET_SELF_BASEDATA)) { @@ -2461,11 +2453,11 @@ exit: cd->hw_ops->send_cmd(cd, &temp_cmd); /* enable irq & esd */ cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); return ret; } -static void goodix_set_sense_mode(struct goodix_ts_core *cd, u8 val) +static void goodix_set_sense_mode(u8 val) { struct goodix_ts_cmd temp_cmd; @@ -2476,26 +2468,26 @@ static void goodix_set_sense_mode(struct goodix_ts_core *cd, u8 val) /* normal mode */ index = sprintf(rbuf, "switch to coordinate mode\n"); cd->hw_ops->send_cmd(cd, &temp_cmd); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); cd->hw_ops->irq_enable(cd, true); atomic_set(&cd->suspended, 0); } else if (val == 2) { /* gesture mode */ index = sprintf(rbuf, "switch to gesture mode\n"); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); cd->hw_ops->gesture(cd, 0); cd->hw_ops->irq_enable(cd, true); atomic_set(&cd->suspended, 1); } else { /* sleep mode */ index = sprintf(rbuf, "switch to sleep mode\n"); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); cd->hw_ops->irq_enable(cd, false); cd->hw_ops->suspend(cd); } } -static void goodix_set_scan_mode(struct goodix_ts_core *cd, u8 val) +static void goodix_set_scan_mode(u8 val) { struct goodix_ts_cmd temp_cmd; @@ -2519,7 +2511,7 @@ static void goodix_set_scan_mode(struct goodix_ts_core *cd, u8 val) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_get_scan_mode(struct goodix_ts_core *cd) +static void goodix_get_scan_mode(void) { u8 status; @@ -2541,7 +2533,7 @@ static void goodix_get_scan_mode(struct goodix_ts_core *cd) } } -static void goodix_set_continue_mode(struct goodix_ts_core *cd, u8 val) +static void goodix_set_continue_mode(u8 val) { struct goodix_ts_cmd temp_cmd; @@ -2559,7 +2551,7 @@ static void goodix_set_continue_mode(struct goodix_ts_core *cd, u8 val) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_read_config(struct goodix_ts_core *cd) +static void goodix_read_config(void) { int ret; u8 *cfg_buf; @@ -2587,7 +2579,7 @@ exit: kfree(cfg_buf); } -static void goodix_get_fw_status(struct goodix_ts_core *cd) +static void goodix_get_fw_status(void) { u32 status_addr; u32 noise_lv_addr; @@ -2634,7 +2626,7 @@ static void goodix_get_fw_status(struct goodix_ts_core *cd) index += sprintf(&rbuf[index], "noise-lv[%d]\n", val); } -static void goodix_set_highsense_mode(struct goodix_ts_core *cd, u8 val) +static void goodix_set_highsense_mode(u8 val) { struct goodix_ts_cmd temp_cmd; static bool flag = false; @@ -2658,7 +2650,7 @@ static void goodix_set_highsense_mode(struct goodix_ts_core *cd, u8 val) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_set_grip_data(struct goodix_ts_core *cd, u8 val) +static void goodix_set_grip_data(u8 val) { struct goodix_ts_cmd temp_cmd; @@ -2687,7 +2679,7 @@ static void goodix_set_grip_data(struct goodix_ts_core *cd, u8 val) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_set_custom_mode(struct goodix_ts_core *cd, u8 type, u8 val) +static void goodix_set_custom_mode(u8 type, u8 val) { struct goodix_ts_cmd temp_cmd; @@ -2739,7 +2731,7 @@ static int obtain_param(char **buf) return val; } -static int goodix_parse_gesture_param(struct goodix_ts_core *cd, u8 type, char **buf) +static int goodix_parse_gesture_param(u8 type, char **buf) { if (type == GESTURE_STTW) { gesture_param_st.length = sizeof(gesture_param_st); @@ -2831,7 +2823,7 @@ static int goodix_parse_gesture_param(struct goodix_ts_core *cd, u8 type, char * return 0; } -static void goodix_set_gesture_param(struct goodix_ts_core *cd, u8 type) +static void goodix_set_gesture_param(u8 type) { struct goodix_ts_cmd temp_cmd; u32 cmd_reg = cd->ic_info.misc.cmd_addr; @@ -2895,29 +2887,18 @@ exit: cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_set_heatmap(struct goodix_ts_core *cd, int val) +static void goodix_set_heatmap(int val) { struct goodix_ts_cmd temp_cmd; cd->hw_ops->irq_enable(cd, false); if (val == 0) { index = sprintf(rbuf, "disable heatmap\n"); -/* - * [GOOG] - * Use goodix_update_heatmap() to do the heatmap process. - kfree(cd->heatmap_buffer); - cd->heatmap_buffer = NULL; - */ temp_cmd.len = 5; temp_cmd.cmd = 0xC9; temp_cmd.data[0] = 0; } else { index = sprintf(rbuf, "enable heatmap\n"); -/* - * [GOOG] - * Use goodix_update_heatmap() to do the heatmap process. - cd->heatmap_buffer = kzalloc(GOODIX_MAX_FRAMEDATA_LEN, GFP_KERNEL); - */ temp_cmd.len = 5; temp_cmd.cmd = 0xC9; temp_cmd.data[0] = 1; @@ -2926,7 +2907,7 @@ static void goodix_set_heatmap(struct goodix_ts_core *cd, int val) cd->hw_ops->irq_enable(cd, true); } -static void goodix_get_self_compensation(struct goodix_ts_core *cd) +static void goodix_get_self_compensation(void) { u8 *cfg; u8 *cfg_buf; @@ -2981,7 +2962,7 @@ exit: kfree(cfg_buf); } -static void goodix_set_report_rate(struct goodix_ts_core *cd, int rate) +static void goodix_set_report_rate(int rate) { struct goodix_ts_cmd temp_cmd; @@ -2994,12 +2975,12 @@ static void goodix_set_report_rate(struct goodix_ts_core *cd, int rate) } #define DUMP_AREA1_ADDR 0x10194 -#define DUMP_AREA1_LEN 132 +#define DUMP_AREA1_LEN 132 #define DUMP_AREA2_ADDR 0x10400 -#define DUMP_AREA2_LEN 596 +#define DUMP_AREA2_LEN 596 #define DUMP_AREA3_ADDR 0x10308 -#define DUMP_AREA3_LEN 64 -static void goodix_get_dump_log(struct goodix_ts_core *cd) +#define DUMP_AREA3_LEN 64 +static void goodix_get_dump_log(void) { u8 buf[600]; int i; @@ -3029,7 +3010,7 @@ static void goodix_get_dump_log(struct goodix_ts_core *cd) } } -static void goodix_get_stylus_data(struct goodix_ts_core *cd) +static void goodix_get_stylus_data(void) { struct goodix_stylus_data stylus_data; u8 temp_buf[40] = { 0 }; @@ -3054,7 +3035,7 @@ static void goodix_get_stylus_data(struct goodix_ts_core *cd) /* disable irq & close esd */ cd->hw_ops->irq_enable(cd, false); - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); /* clean touch event flag */ ret = cd->hw_ops->write(cd, flag_addr, temp_buf, 1); @@ -3145,10 +3126,10 @@ static void goodix_get_stylus_data(struct goodix_ts_core *cd) exit: /* enable irq & esd */ cd->hw_ops->irq_enable(cd, true); - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); } -static void goodix_force_update(struct goodix_ts_core *cd) +static void goodix_force_update(void) { int i; int ret; @@ -3162,7 +3143,7 @@ static void goodix_force_update(struct goodix_ts_core *cd) if (ret < 0) ts_err("not found valid config"); - ret = goodix_do_fw_update(cd, + ret = goodix_do_fw_update(cd->ic_configs[CONFIG_TYPE_NORMAL], UPDATE_MODE_BLOCK | UPDATE_MODE_FORCE | UPDATE_MODE_SRC_REQUEST); if (ret < 0) @@ -3171,7 +3152,7 @@ static void goodix_force_update(struct goodix_ts_core *cd) index = sprintf(rbuf, "%s: OK\n", CMD_FW_UPDATE); } -static void goodix_set_freq_index(struct goodix_ts_core *cd, int freq) +static void goodix_set_freq_index(int freq) { struct goodix_ts_cmd temp_cmd; @@ -3183,7 +3164,7 @@ static void goodix_set_freq_index(struct goodix_ts_core *cd, int freq) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static void goodix_disable_coor_filter(struct goodix_ts_core *cd, int val) +static void goodix_disable_coor_filter(int val) { struct goodix_ts_cmd temp_cmd; @@ -3194,11 +3175,9 @@ static void goodix_disable_coor_filter(struct goodix_ts_core *cd, int val) cd->hw_ops->send_cmd(cd, &temp_cmd); } -static ssize_t driver_test_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) +static ssize_t driver_test_write( + struct file *file, const char __user *buf, size_t count, loff_t *pos) { - struct seq_file *seq_file = (struct seq_file *)file->private_data; - struct goodix_ts_core *cd = (struct goodix_ts_core *)seq_file->private; struct goodix_fw_version fw_ver; struct goodix_ic_info ic_info; char *p = wbuf; @@ -3218,7 +3197,6 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("copy from user failed"); return count; } - p[strlen(p) - 1] = 0; vfree(rbuf); rbuf = NULL; @@ -3229,7 +3207,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, if (!strncmp(p, CMD_FW_UPDATE, strlen(CMD_FW_UPDATE))) { rbuf = vzalloc(SHORT_SIZE); - goodix_force_update(cd); + goodix_force_update(); goto exit; } @@ -3254,7 +3232,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_RAWDATA); + ret = get_cap_data(CMD_GET_RAWDATA); if (ret < 0) { index = sprintf(rbuf, "%s: NG\n", CMD_GET_RAWDATA); } @@ -3267,7 +3245,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_BASEDATA); + ret = get_cap_data(CMD_GET_BASEDATA); if (ret < 0) { index = sprintf(rbuf, "%s: NG\n", CMD_GET_BASEDATA); } @@ -3280,7 +3258,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_DIFFDATA); + ret = get_cap_data(CMD_GET_DIFFDATA); if (ret < 0) { index = sprintf(rbuf, "%s: NG\n", CMD_GET_DIFFDATA); } @@ -3293,7 +3271,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_SELF_RAWDATA); + ret = get_cap_data(CMD_GET_SELF_RAWDATA); if (ret < 0) { index = sprintf(rbuf, "%s: NG\n", CMD_GET_SELF_RAWDATA); } @@ -3306,7 +3284,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_SELF_DIFFDATA); + ret = get_cap_data(CMD_GET_SELF_DIFFDATA); if (ret < 0) { index = sprintf( rbuf, "%s: NG\n", CMD_GET_SELF_DIFFDATA); @@ -3320,7 +3298,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_SELF_BASEDATA); + ret = get_cap_data(CMD_GET_SELF_BASEDATA); if (ret < 0) { index = sprintf( rbuf, "%s: NG\n", CMD_GET_SELF_BASEDATA); @@ -3468,11 +3446,11 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, goto exit; } if (cmd_val == 0) { - goodix_ts_esd_off(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); index = sprintf( rbuf, "%s: disable OK\n", CMD_SET_ESD_ENABLE); } else { - goodix_ts_esd_on(cd); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); index = sprintf( rbuf, "%s: enable OK\n", CMD_SET_ESD_ENABLE); } @@ -3526,7 +3504,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_test->item[GTP_DELTA_TEST] = true; ts_test->item[GTP_SELFCAP_TEST] = true; ts_test->item[GTP_SHORT_TEST] = true; - goodix_auto_test(cd, true); + goodix_auto_test(true); goto exit; } @@ -3547,7 +3525,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - ret = get_cap_data(cd, CMD_GET_TX_FREQ); + ret = get_cap_data(CMD_GET_TX_FREQ); if (ret < 0) { index = sprintf(rbuf, "%s: NG\n", CMD_GET_TX_FREQ); } @@ -3583,7 +3561,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_SENSE_MODE); goto exit; } - goodix_set_sense_mode(cd, cmd_val); + goodix_set_sense_mode(cmd_val); goto exit; } @@ -3609,7 +3587,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, goto exit; } ts_test->item[GTP_NOISE_TEST] = true; - goodix_auto_test(cd, false); + goodix_auto_test(false); goto exit; } @@ -3637,7 +3615,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - goodix_auto_noise_test(cd, cmd_val, cmd_val2); + goodix_auto_noise_test(cmd_val, cmd_val2); goto exit; } @@ -3649,7 +3627,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, } mutex_lock(&cd->cmd_lock); usleep_range(6000, 6100); - ret = goodix_flash_read(cd, 0x1F301, &id, 1); + ret = goodix_flash_read(0x1F301, &id, 1); mutex_unlock(&cd->cmd_lock); if (ret < 0) index = sprintf(rbuf, "%s: NG\n", CMD_GET_PACKAGE_ID); @@ -3667,7 +3645,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, } mutex_lock(&cd->cmd_lock); usleep_range(6000, 6100); - ret = goodix_flash_read(cd, 0x1F314, &id, 1); + ret = goodix_flash_read(0x1F314, &id, 1); mutex_unlock(&cd->cmd_lock); if (ret < 0) index = sprintf(rbuf, "%s: NG\n", CMD_GET_MCU_ID); @@ -3698,7 +3676,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_SCAN_MODE); goto exit; } - goodix_set_scan_mode(cd, cmd_val); + goodix_set_scan_mode(cmd_val); goto exit; } @@ -3708,7 +3686,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - goodix_get_scan_mode(cd); + goodix_get_scan_mode(); goto exit; } @@ -3734,7 +3712,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_CONTINUE_MODE); goto exit; } - goodix_set_continue_mode(cd, cmd_val); + goodix_set_continue_mode(cmd_val); goto exit; } @@ -3771,7 +3749,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, } ts_test->item[GTP_CAP_TEST] = true; ts_test->freq = cmd_val2; - goodix_auto_test(cd, false); + goodix_auto_test(false); goto exit; } @@ -3787,7 +3765,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, goto exit; } ts_test->item[GTP_SELFCAP_TEST] = true; - goodix_auto_test(cd, false); + goodix_auto_test(false); goto exit; } @@ -3803,7 +3781,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, goto exit; } ts_test->item[GTP_SHORT_TEST] = true; - goodix_auto_test(cd, false); + goodix_auto_test(false); goto exit; } @@ -3813,7 +3791,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - goodix_read_config(cd); + goodix_read_config(); goto exit; } @@ -3823,7 +3801,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - goodix_get_fw_status(cd); + goodix_get_fw_status(); goto exit; } @@ -3850,7 +3828,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_HIGHSENSE_MODE); goto exit; } - goodix_set_highsense_mode(cd, cmd_val); + goodix_set_highsense_mode(cmd_val); goto exit; } @@ -3871,7 +3849,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_GRIP_DATA); goto exit; } - goodix_set_grip_data(cd, cmd_val); + goodix_set_grip_data(cmd_val); goto exit; } @@ -3892,7 +3870,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_GRIP_MODE); goto exit; } - goodix_set_custom_mode(cd, GRIP_FUNC, cmd_val); + goodix_set_custom_mode(GRIP_FUNC, cmd_val); goto exit; } @@ -3913,7 +3891,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_PALM_MODE); goto exit; } - goodix_set_custom_mode(cd, PALM_FUNC, cmd_val); + goodix_set_custom_mode(PALM_FUNC, cmd_val); goto exit; } @@ -3934,7 +3912,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_NOISE_MODE); goto exit; } - goodix_set_custom_mode(cd, NOISE_FUNC, cmd_val); + goodix_set_custom_mode(NOISE_FUNC, cmd_val); goto exit; } @@ -3955,7 +3933,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_WATER_MODE); goto exit; } - goodix_set_custom_mode(cd, WATER_FUNC, cmd_val); + goodix_set_custom_mode(WATER_FUNC, cmd_val); goto exit; } @@ -3971,8 +3949,8 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_ST_PARAM); goto exit; } - goodix_parse_gesture_param(cd, GESTURE_STTW, &p); - goodix_set_gesture_param(cd, GESTURE_STTW); + goodix_parse_gesture_param(GESTURE_STTW, &p); + goodix_set_gesture_param(GESTURE_STTW); goto exit; } @@ -3988,8 +3966,8 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_LP_PARAM); goto exit; } - goodix_parse_gesture_param(cd, GESTURE_LPTW, &p); - goodix_set_gesture_param(cd, GESTURE_LPTW); + goodix_parse_gesture_param(GESTURE_LPTW, &p); + goodix_set_gesture_param(GESTURE_LPTW); goto exit; } @@ -4010,7 +3988,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_HEATMAP); goto exit; } - goodix_set_heatmap(cd, cmd_val); + goodix_set_heatmap(cmd_val); goto exit; } @@ -4020,7 +3998,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, ts_err("failed to alloc rbuf"); goto exit; } - goodix_get_self_compensation(cd); + goodix_get_self_compensation(); goto exit; } @@ -4041,27 +4019,25 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_REPORT_RATE); goto exit; } - goodix_set_report_rate(cd, cmd_val); + goodix_set_report_rate(cmd_val); goto exit; } if (!strncmp(p, CMD_GET_DUMP_LOG, strlen(CMD_GET_DUMP_LOG))) { rbuf = vzalloc(LARGE_SIZE); - if (!rbuf) { - ts_err("failed to alloc rbuf"); - goto exit; - } - goodix_get_dump_log(cd); + goodix_get_dump_log(); + goto exit; + } + if (!strncmp(p, CMD_GET_STYLUS_DATA, strlen(CMD_GET_STYLUS_DATA))) { + rbuf = vzalloc(LARGE_SIZE); + goodix_get_stylus_data(); goto exit; } + if (!strncmp(p, CMD_GET_STYLUS_DATA, strlen(CMD_GET_STYLUS_DATA))) { rbuf = vzalloc(LARGE_SIZE); - if (!rbuf) { - ts_err("failed to alloc rbuf"); - goto exit; - } - goodix_get_stylus_data(cd); + goodix_get_stylus_data(); goto exit; } @@ -4078,7 +4054,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_SET_FREQ_INDEX); goto exit; } - goodix_set_freq_index(cd, cmd_val); + goodix_set_freq_index(cmd_val); goto exit; } @@ -4095,7 +4071,7 @@ static ssize_t driver_test_write(struct file *file, const char __user *buf, CMD_DISABLE_FILTER); goto exit; } - goodix_disable_coor_filter(cd, cmd_val); + goodix_disable_coor_filter(cmd_val); goto exit; } @@ -4162,8 +4138,7 @@ static const struct file_operations cmd_list_ops = { }; #endif -/* [GOOG] */ -int driver_test_selftest(struct goodix_ts_core *cd, char *buf) +int driver_test_selftest(char* buf) { int ret = 0; @@ -4192,7 +4167,7 @@ int driver_test_selftest(struct goodix_ts_core *cd, char *buf) ts_test->item[GTP_DELTA_TEST] = true; ts_test->item[GTP_SELFCAP_TEST] = true; ts_test->item[GTP_SHORT_TEST] = true; - goodix_auto_test(cd, true); + goodix_auto_test(true); strlcpy(buf, rbuf, PAGE_SIZE); @@ -4204,24 +4179,22 @@ int driver_test_proc_init(struct goodix_ts_core *core_data) { struct proc_dir_entry *proc_entry; - proc_entry = proc_create_data( - "driver_test", 0660, core_data->proc_dir_entry, &driver_test_ops, core_data); + proc_entry = proc_create( + "goodix_ts/driver_test", 0660, NULL, &driver_test_ops); if (!proc_entry) { - ts_err("failed to create proc driver_test"); - return -ENODEV; + ts_err("failed to create proc entry"); + return -ENOMEM; } proc_entry = - proc_create("cmd_list", 0440, core_data->proc_dir_entry, &cmd_list_ops); - if (!proc_entry) { - ts_err("failed to create proc cmd_list"); - return -ENODEV; - } + proc_create("goodix_ts/cmd_list", 0440, NULL, &cmd_list_ops); + + cd = core_data; return 0; } -void driver_test_proc_remove(struct goodix_ts_core *core_data) +void driver_test_proc_remove(void) { - remove_proc_entry("cmd_list", core_data->proc_dir_entry); - remove_proc_entry("driver_test", core_data->proc_dir_entry); + remove_proc_entry("goodix_ts/cmd_list", NULL); + remove_proc_entry("goodix_ts/driver_test", NULL); } diff --git a/goodix_ts_tools.c b/goodix_ts_tools.c index f648ba0..5fb175f 100644 --- a/goodix_ts_tools.c +++ b/goodix_ts_tools.c @@ -20,14 +20,15 @@ #include <linux/ioctl.h> #include <linux/kernel.h> #include <linux/list.h> +#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/wait.h> -#define GOODIX_TOOLS_NAME "gtp_tools" -#define GOODIX_TOOLS_VER_MAJOR 1 -#define GOODIX_TOOLS_VER_MINOR 0 +#define GOODIX_TOOLS_NAME "gtp_tools" +#define GOODIX_TOOLS_VER_MAJOR 1 +#define GOODIX_TOOLS_VER_MINOR 0 static const u16 goodix_tools_ver = ((GOODIX_TOOLS_VER_MAJOR << 8) + (GOODIX_TOOLS_VER_MINOR)); @@ -48,9 +49,33 @@ static const u16 goodix_tools_ver = (_IOW(GOODIX_TS_IOC_MAGIC, 10, u8) & NEGLECT_SIZE_MASK) #define MAX_BUF_LENGTH (16 * 1024) +#define IRQ_FALG (0x01 << 2) #define I2C_MSG_HEAD_LEN 20 +/* + * struct goodix_tools_dev - goodix tools device struct + * @ts_core: The core data struct of ts driver + * @ops_mode: represent device work mode + * @rawdiffcmd: Set slave device into rawdata mode + * @normalcmd: Set slave device into normal mode + * @wq: Wait queue struct use in synchronous data read + * @mutex: Protect goodix_tools_dev + * @in_use: device in use + */ +struct goodix_tools_dev { + struct goodix_ts_core *ts_core; + struct list_head head; + unsigned int ops_mode; + struct goodix_ts_cmd rawdiffcmd, normalcmd; + wait_queue_head_t wq; + bool is_clean_flag; + struct delayed_work sync_work; + struct mutex mutex; + atomic_t in_use; + struct goodix_ext_module module; +} *goodix_tools_dev; + /* read data asynchronous, * success return data length, otherwise return < 0 */ @@ -60,9 +85,7 @@ static int async_read(struct goodix_tools_dev *dev, void __user *arg) int ret = 0; u32 reg_addr, length; u8 i2c_msg_head[I2C_MSG_HEAD_LEN]; - struct goodix_ts_core *ts_core = - container_of(dev, struct goodix_ts_core, tools_dev); - const struct goodix_ts_hw_ops *hw_ops = ts_core->hw_ops; + const struct goodix_ts_hw_ops *hw_ops = dev->ts_core->hw_ops; ret = copy_from_user(&i2c_msg_head, arg, I2C_MSG_HEAD_LEN); if (ret) @@ -82,7 +105,7 @@ static int async_read(struct goodix_tools_dev *dev, void __user *arg) return -ENOMEM; } - if (hw_ops->read(ts_core, reg_addr, databuf, length)) { + if (hw_ops->read(dev->ts_core, reg_addr, databuf, length)) { ret = -EBUSY; ts_err("Read i2c failed"); goto err_out; @@ -160,8 +183,7 @@ static int async_write(struct goodix_tools_dev *dev, void __user *arg) int ret = 0; u32 reg_addr, length; u8 i2c_msg_head[I2C_MSG_HEAD_LEN]; - struct goodix_ts_core *ts_core = - container_of(dev, struct goodix_ts_core, tools_dev); + struct goodix_ts_core *ts_core = dev->ts_core; const struct goodix_ts_hw_ops *hw_ops = ts_core->hw_ops; ret = copy_from_user(&i2c_msg_head, arg, I2C_MSG_HEAD_LEN); @@ -197,6 +219,9 @@ static int async_write(struct goodix_tools_dev *dev, void __user *arg) ret = length; } + if (reg_addr == ts_core->ic_info.misc.touch_data_addr) + dev->is_clean_flag = true; + err_out: kfree(databuf); return ret; @@ -229,6 +254,29 @@ static int init_cfg_data(struct goodix_ic_config *cfg, void __user *arg) return 0; } +static void goodix_ctrl_sync_work(struct work_struct *work) +{ + struct goodix_ts_core *cd = goodix_tools_dev->ts_core; + static int cnt; + + if (atomic_read(&goodix_tools_dev->in_use) == 0) + return; + + if (cd->tools_ctrl_sync && !goodix_tools_dev->is_clean_flag) { + cnt++; + if (cnt >= 2) { + cnt = 0; + cd->tools_ctrl_sync = false; + ts_info("restore tools sync flag to 0"); + } + } else { + cnt = 0; + } + + goodix_tools_dev->is_clean_flag = false; + schedule_delayed_work(&goodix_tools_dev->sync_work, 5 * HZ); +} + /** * goodix_tools_ioctl - ioctl implementation * @@ -242,15 +290,15 @@ static long goodix_tools_ioctl( { int ret = 0; struct goodix_tools_dev *dev = filp->private_data; - struct goodix_ts_core *ts_core = - container_of(dev, struct goodix_ts_core, tools_dev); + struct goodix_ts_core *ts_core; const struct goodix_ts_hw_ops *hw_ops; struct goodix_ic_config *temp_cfg = NULL; - if (ts_core == NULL) { + if (dev->ts_core == NULL) { ts_err("Tools module not register"); return -EINVAL; } + ts_core = dev->ts_core; hw_ops = ts_core->hw_ops; if (_IOC_TYPE(cmd) != GOODIX_TS_IOC_MAGIC) { @@ -262,9 +310,15 @@ static long goodix_tools_ioctl( case GTP_IRQ_ENABLE: if (arg == 1) { hw_ops->irq_enable(ts_core, true); + mutex_lock(&dev->mutex); + dev->ops_mode |= IRQ_FALG; + mutex_unlock(&dev->mutex); ts_info("IRQ enabled"); } else if (arg == 0) { hw_ops->irq_enable(ts_core, false); + mutex_lock(&dev->mutex); + dev->ops_mode &= ~IRQ_FALG; + mutex_unlock(&dev->mutex); ts_info("IRQ disabled"); } else { ts_info("Irq aready set with, arg = %ld", arg); @@ -273,9 +327,9 @@ static long goodix_tools_ioctl( break; case GTP_ESD_ENABLE: if (arg == 0) - goodix_ts_esd_off(ts_core); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); else - goodix_ts_esd_on(ts_core); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); break; case GTP_DEV_RESET: hw_ops->reset(ts_core, GOODIX_NORMAL_RESET_DELAY_MS); @@ -292,6 +346,7 @@ static long goodix_tools_ioctl( ret = -ENOMEM; goto err_out; } + ret = init_cfg_data(temp_cfg, (void __user *)arg); if (!ret && hw_ops->send_config) { ret = hw_ops->send_config( @@ -358,49 +413,59 @@ static long goodix_tools_compat_ioctl( } #endif -static struct goodix_ts_core *core_data_locate(int minor) +static int goodix_tools_open(struct inode *inode, struct file *filp) { - struct goodix_device_resource *res, *next; + int ret = 0; - if (!list_empty(&goodix_devices.list)) { - list_for_each_entry_safe(res, next, &goodix_devices.list, list) { - if (res->core_data.tools_dev.miscdev.minor == minor) - return &res->core_data; - } + ts_info("try open tool"); + /* Only the first time open device need to register module */ + ret = goodix_register_ext_module_no_wait(&goodix_tools_dev->module); + if (ret) { + ts_info("failed register to core module"); + return -EFAULT; } + ts_info("success open tools"); + goodix_ts_blocking_notify(NOTIFY_ESD_OFF, NULL); + filp->private_data = goodix_tools_dev; + atomic_set(&goodix_tools_dev->in_use, 1); + schedule_delayed_work(&goodix_tools_dev->sync_work, 5 * HZ); + return 0; +} - return NULL; +static int goodix_tools_release(struct inode *inode, struct file *filp) +{ + int ret = 0; + /* when the last close this dev node unregister the module */ + goodix_tools_dev->ts_core->tools_ctrl_sync = false; + atomic_set(&goodix_tools_dev->in_use, 0); + cancel_delayed_work_sync(&goodix_tools_dev->sync_work); + goodix_ts_blocking_notify(NOTIFY_ESD_ON, NULL); + ret = goodix_unregister_ext_module(&goodix_tools_dev->module); + return ret; } -static int goodix_tools_open(struct inode *inode, struct file *filp) +static int goodix_tools_module_init( + struct goodix_ts_core *core_data, struct goodix_ext_module *module) { - struct goodix_ts_core *cd = core_data_locate(iminor(inode)); + struct goodix_tools_dev *tools_dev = module->priv_data; - if (!cd) { - ts_err("can't find core data"); + if (core_data) + tools_dev->ts_core = core_data; + else return -ENODEV; - } - goodix_ts_esd_off(cd); - cd->tools_dev.is_open = true; - filp->private_data = &cd->tools_dev; - ts_info("success open tools"); return 0; } -static int goodix_tools_release( - struct inode *inode, struct file *filp) +static int goodix_tools_module_exit( + struct goodix_ts_core *core_data, struct goodix_ext_module *module) { - struct goodix_ts_core *cd = core_data_locate(iminor(inode)); - - if (!cd) { - ts_err("can't find core data"); - return -ENODEV; + struct goodix_tools_dev *tools_dev = module->priv_data; + ts_debug("tools module unregister"); + if (atomic_read(&tools_dev->in_use)) { + ts_err("tools module busy, please close it then retry"); + return -EBUSY; } - /* when the last close this dev node unregister the module */ - cd->tools_dev.is_open = false; - cd->tools_ctrl_sync = false; - goodix_ts_esd_on(cd); return 0; } @@ -414,21 +479,46 @@ static const struct file_operations goodix_tools_fops = { #endif }; +static struct miscdevice goodix_tools_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = GOODIX_TOOLS_NAME, + .fops = &goodix_tools_fops, +}; + +static struct goodix_ext_module_funcs goodix_tools_module_funcs = { + .init = goodix_tools_module_init, + .exit = goodix_tools_module_exit, +}; + /** * goodix_tools_init - init goodix tools device and register a miscdevice * * return: 0 success, else failed */ -int goodix_tools_init(struct goodix_ts_core *core_data) +int goodix_tools_init(void) { int ret; - struct goodix_tools_dev *tools_dev = &core_data->tools_dev; - sprintf(tools_dev->name, "%s.%d", GOODIX_TOOLS_NAME, core_data->pdev->id); - tools_dev->miscdev.minor = MISC_DYNAMIC_MINOR; - tools_dev->miscdev.name = tools_dev->name; - tools_dev->miscdev.fops = &goodix_tools_fops; - ret = misc_register(&tools_dev->miscdev); + goodix_tools_dev = kzalloc(sizeof(struct goodix_tools_dev), GFP_KERNEL); + if (goodix_tools_dev == NULL) { + ts_err("Memory allco err"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&goodix_tools_dev->head); + goodix_tools_dev->ops_mode = 0; + goodix_tools_dev->ops_mode |= IRQ_FALG; + init_waitqueue_head(&goodix_tools_dev->wq); + mutex_init(&goodix_tools_dev->mutex); + atomic_set(&goodix_tools_dev->in_use, 0); + + goodix_tools_dev->module.funcs = &goodix_tools_module_funcs; + goodix_tools_dev->module.name = GOODIX_TOOLS_NAME; + goodix_tools_dev->module.priv_data = goodix_tools_dev; + goodix_tools_dev->module.priority = EXTMOD_PRIO_DBGTOOL; + INIT_DELAYED_WORK(&goodix_tools_dev->sync_work, goodix_ctrl_sync_work); + + ret = misc_register(&goodix_tools_miscdev); if (ret) ts_err("Debug tools miscdev register failed"); else @@ -437,10 +527,9 @@ int goodix_tools_init(struct goodix_ts_core *core_data) return ret; } -void goodix_tools_exit(struct goodix_ts_core *core_data) +void goodix_tools_exit(void) { - struct goodix_tools_dev *tools_dev = &core_data->tools_dev; - - misc_deregister(&tools_dev->miscdev); + misc_deregister(&goodix_tools_miscdev); + kfree(goodix_tools_dev); ts_info("Debug tools miscdev exit"); } diff --git a/goodix_ts_utils.c b/goodix_ts_utils.c index c3fc33e..7649759 100644 --- a/goodix_ts_utils.c +++ b/goodix_ts_utils.c @@ -69,7 +69,7 @@ int checksum_cmp(const u8 *data, int size, int mode) u32 cal_checksum = 0; u32 r_checksum = 0; u32 i; - bool is_valid = !is_risk_data(data, size); /* [GOOG] */ + bool is_valid = !is_risk_data(data, size); if (mode == CHECKSUM_MODE_U8_LE) { if (size < 2) @@ -123,11 +123,7 @@ u32 goodix_get_file_config_id(u8 *ic_config) return le32_to_cpup((__le32 *)&ic_config[CONFIG_ID_OFFSET]); } -/* - * matrix transpose: - * [GOOG] - * Add 'dest' as optional target(pa/2221748). - */ +/* matrix transpose */ void goodix_rotate_abcd2cbad(int tx, int rx, s16 *src, s16 *dest) { s16 *temp_buf = dest; @@ -136,14 +132,10 @@ void goodix_rotate_abcd2cbad(int tx, int rx, s16 *src, s16 *dest) s16 *curr; int index_org = 0; - /* - * [GOOG] - * If no 'dest' assign, 'src' will be overwrote. - */ if (dest == NULL) { temp_buf = kcalloc(size, sizeof(s16), GFP_KERNEL); if (!temp_buf) { - ts_err("%s: malloc failed!\n", __func__); + ts_err("malloc failed"); return; } } @@ -160,7 +152,6 @@ void goodix_rotate_abcd2cbad(int tx, int rx, s16 *src, s16 *dest) memcpy(src, temp_buf, size * sizeof(s16)); kfree(temp_buf); } - /*~[GOOG] */ } /* get ic type */ |