//****************************************************************************** /// \brief Disable noise suppression objects static void disable_noise_suppression(struct mxt_device *mxt) { uint16_t addr; uint8_t disable = 0; addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T22, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T48, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T54, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } addr = mxt_get_object_address(mxt, PROCG_NOISESUPPRESSION_T62, 0); if (addr != OBJECT_NOT_FOUND) { mxt_write_register(mxt, &disable, addr, 1); } }
//****************************************************************************** /// \brief Retrieve a single page of diagnostic data /// \return #mxt_rc static int mxt_get_t37_page(struct t37_ctx *ctx) { int failures; int ret; uint8_t read_command = 1; uint8_t page_up_cmd = PAGE_UP; if (ctx->pass == 0 && ctx->page == 0) { mxt_dbg(ctx->lc, "Writing mode command %02X", ctx->mode); ret = mxt_write_register(ctx->mxt, &ctx->mode, ctx->diag_cmd_addr, 1); if (ret) return ret; } else { ret = mxt_write_register(ctx->mxt, &page_up_cmd, ctx->diag_cmd_addr, 1); if (ret) return ret; } /* Read back diagnostic register in T6 command processor until it has been * cleared. This means that the chip has actioned the command */ failures = 0; while (read_command) { usleep(500); ret = mxt_read_register(ctx->mxt, &read_command, ctx->diag_cmd_addr, 1); if (ret) { mxt_err(ctx->lc, "Failed to read the status of diagnostic mode command"); return ret; } if (read_command) { failures++; if (failures > 500) { mxt_err(ctx->lc, "Timeout waiting for command to be actioned"); return MXT_ERROR_TIMEOUT; } } } ret = mxt_read_register(ctx->mxt, (uint8_t *)ctx->t37_buf, ctx->t37_addr, ctx->t37_size); if (ret) { mxt_err(ctx->lc, "Failed to read page"); return ret; } if (ctx->t37_buf->mode != ctx->mode) { mxt_err(ctx->lc, "Bad mode in diagnostic data read"); return MXT_ERROR_UNEXPECTED_DEVICE_STATE; } if (ctx->t37_buf->page != (ctx->pages_per_pass * ctx->pass + ctx->page)) { mxt_err(ctx->lc, "Bad page in diagnostic data read"); return MXT_ERROR_UNEXPECTED_DEVICE_STATE; } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Perform fallback reset /// \return #mxt_rc static int mxt_send_reset_command(struct mxt_device *mxt, bool bootloader_mode) { int ret; uint16_t t6_addr; unsigned char write_value = RESET_COMMAND; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* The value written determines which mode the chip will boot into */ if (bootloader_mode) { mxt_info(mxt->ctx, "Resetting in bootloader mode"); write_value = BOOTLOADER_COMMAND; } else { mxt_info(mxt->ctx, "Sending reset command"); } /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &write_value, t6_addr + MXT_T6_RESET_OFFSET, 1 ); return ret; }
//****************************************************************************** /// \brief Write DATATYPE /// \return #mxt_rc static int mxt_t68_write_datatype(struct t68_ctx *ctx) { uint8_t buf[2]; buf[0] = (ctx->t68_datatype & 0xFF); buf[1] = (ctx->t68_datatype & 0xFF00) >> 8; mxt_info(ctx->lc, "Writing %u to DATATYPE register", ctx->t68_datatype); return mxt_write_register(ctx->mxt, &buf[0], ctx->t68_addr + T68_DATATYPE, sizeof(buf)); }
//****************************************************************************** /// \brief Send command then check status /// \return #mxt_rc static int mxt_t68_command(struct t68_ctx *ctx, uint8_t cmd) { int ret; mxt_verb(ctx->lc, "Writing %u to CMD register", cmd); ret = mxt_write_register(ctx->mxt, &cmd, ctx->t68_cmd_addr, 1); if (ret) return ret; return mxt_read_messages_sigint(ctx->mxt, T68_TIMEOUT, ctx, mxt_t68_get_status); }
//****************************************************************************** /// \brief Zero entire T68 object /// \return #mxt_rc static int mxt_t68_zero_data(struct t68_ctx *ctx) { uint8_t zeros[ctx->t68_data_size]; mxt_dbg(ctx->lc, "Zeroing DATA"); memset(&zeros, 0, sizeof(zeros)); return mxt_write_register(ctx->mxt, zeros, ctx->t68_addr + T68_DATA, sizeof(zeros)); }
//****************************************************************************** /// \brief Run self test int run_self_tests(struct mxt_device *mxt, uint8_t cmd) { uint16_t t25_addr; uint8_t enable = 3; mxt_msg_reset(mxt); // Enable self test object & reporting t25_addr = mxt_get_object_address(mxt, SPT_SELFTEST_T25, 0); mxt_info(mxt->ctx, "Enabling self test object"); mxt_write_register(mxt, &enable, t25_addr, 1); mxt_info(mxt->ctx, "Disabling noise suppression"); disable_noise_suppression(mxt); print_t25_limits(mxt, t25_addr); mxt_info(mxt->ctx, "Running tests"); mxt_write_register(mxt, &cmd, t25_addr + 1, 1); return self_test_handle_messages(mxt); }
//****************************************************************************** /// \brief Enable T68 /// \return #mxt_rc static int mxt_t68_enable(struct t68_ctx *ctx) { int ret; uint8_t cmd = T68_CTRL_RPTEN | T68_CTRL_ENABLE; mxt_dbg(ctx->lc, "Enabling T68 object"); mxt_verb(ctx->lc, "Writing %u to ctrl register", cmd); ret = mxt_write_register(ctx->mxt, &cmd, ctx->t68_addr + T68_CTRL, 1); if (ret) return ret; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Send frames of T68 data to chip /// \return #mxt_rc static int mxt_t68_send_frames(struct t68_ctx *ctx) { int ret; size_t offset = 0; uint16_t frame_size; int frame = 1; uint8_t cmd; while (offset < ctx->buf.size) { frame_size = MIN(ctx->buf.size - offset, ctx->t68_data_size); mxt_info(ctx->lc, "Writing frame %u, %u bytes", frame, frame_size); if (frame_size > UCHAR_MAX) { mxt_err(ctx->lc, "Serial data frame size miscalculation"); return MXT_INTERNAL_ERROR; } ret = mxt_write_register(ctx->mxt, ctx->buf.data + offset, ctx->t68_addr + T68_DATA, frame_size); if (ret) return ret; ret = mxt_t68_write_length(ctx, frame_size); if (ret) return ret; offset += frame_size; if (frame == 1) cmd = T68_CMD_START; else if (offset >= ctx->buf.size) cmd = T68_CMD_END; else cmd = T68_CMD_CONTINUE; ret = mxt_t68_command(ctx, cmd); if (ret) return ret; frame++; } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Handle bridge write /// \return #mxt_rc static int bridge_wri_cmd(struct mxt_device *mxt, int sockfd, uint16_t address, char *hex, uint16_t bytes) { int ret; uint16_t count; const char * const FAIL = "WRP ERR\n"; const char * const PASS = "******"; const char *response; uint8_t *databuf; databuf = calloc(bytes, sizeof(uint8_t)); if (!databuf) { mxt_err(mxt->ctx, "Failed to allocate memory"); return MXT_ERROR_NO_MEM; } ret = mxt_convert_hex(hex, databuf, &count, bytes); if (ret) { response = FAIL; } else { ret = mxt_write_register(mxt, databuf, address, count); if (ret) { mxt_verb(mxt->ctx, "WRI OK"); response = FAIL; } else { response = PASS; } } ret = write(sockfd, response, strlen(response)); if (ret < 0) { mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } ret = MXT_SUCCESS; free(databuf); return ret; }
//****************************************************************************** /// \brief Backup configuration settings to non-volatile memory /// \return #mxt_rc int mxt_backup_config(struct mxt_device *mxt, uint8_t backup_command) { int ret; uint16_t t6_addr; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &backup_command, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1 ); if (ret == MXT_SUCCESS) mxt_info(mxt->ctx, "Backed up settings to the non-volatile memory"); else mxt_err(mxt->ctx, "Failed to back up settings"); return ret; }
//****************************************************************************** /// \brief Issue REPORTALL command to device /// \return #mxt_rc int mxt_report_all(struct mxt_device *mxt) { int ret; uint16_t t6_addr; const uint8_t report_all_cmd = 0xff; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; /* Write to command processor register to perform command */ ret = mxt_write_register ( mxt, &report_all_cmd, t6_addr + MXT_T6_REPORTALL_OFFSET, 1 ); if (ret == MXT_SUCCESS) mxt_info(mxt->ctx, "REPORTALL command issued"); else mxt_err(mxt->ctx, "Failed to issue REPORTALL command"); return ret; }
//****************************************************************************** /// \brief Calibrate maxtouch chip /// \return 0 = success, negative = fail int mxt_calibrate_chip(struct mxt_device *mxt) { int ret; uint16_t t6_addr; unsigned char write_value = CALIBRATE_COMMAND; /* Obtain command processor's address */ t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; mxt_flush_msgs(mxt); /* Write to command processor register to perform command */ ret = mxt_write_register(mxt, &write_value, t6_addr + MXT_T6_CALIBRATE_OFFSET, 1); if (ret == 0) { mxt_info(mxt->ctx, "Sent calibration command"); } else { mxt_err(mxt->ctx, "Failed to send calibration command"); } int state = 0; int flag = false; ret = mxt_read_messages(mxt, MXT_CALIBRATE_TIMEOUT, &state, handle_calibrate_msg, &flag); if (ret == MXT_ERROR_TIMEOUT) { mxt_warn(mxt->ctx, "WARN: timed out waiting for calibrate status"); return MXT_SUCCESS; } else if (ret) { mxt_err(mxt->ctx, "FAIL: device calibration failed"); return ret; } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Run self cap tuning procedure without updating the config /// checksum /// \return #mxt_rc int mxt_self_cap_tune(struct mxt_device *mxt, mxt_app_cmd cmd) { int ret; uint16_t t6_addr; uint16_t t109_addr; uint8_t backupnv_value; uint8_t t109_command; mxt_msg_reset(mxt); // Enable self test object & reporting t6_addr = mxt_get_object_address(mxt, GEN_COMMANDPROCESSOR_T6, 0); if (t6_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; t109_addr = mxt_get_object_address(mxt, SPT_SELFCAPGLOBALCONFIG_T109, 0); if (t109_addr == OBJECT_NOT_FOUND) return MXT_ERROR_OBJECT_NOT_FOUND; mxt_info(mxt->ctx, "Stopping T70"); backupnv_value = 0x33; ret = mxt_write_register(mxt, &backupnv_value, t6_addr + MXT_T6_BACKUPNV_OFFSET, 1); if (ret) return ret; // Wait for backup operation to complete (otherwise T109 report may be missed) mxt_msg_wait(mxt, 100); mxt_info(mxt->ctx, "Tuning"); t109_command = T109_CMD_TUNE; mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd); ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1); if (ret) return ret; ret = mxt_read_messages(mxt, T109_TIMEOUT, &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx); if (ret) return ret; switch (cmd) { case CMD_SELF_CAP_TUNE_CONFIG: mxt_info(mxt->ctx, "Store to Config"); t109_command = T109_CMD_STORE_TO_CONFIG_RAM; break; default: case CMD_SELF_CAP_TUNE_NVRAM: mxt_info(mxt->ctx, "Store to NVRAM"); t109_command = T109_CMD_STORE_TO_NVM; break; } mxt_info(mxt->ctx, "Writing %u to T109 CMD register", cmd); ret = mxt_write_register(mxt, &t109_command, t109_addr + T109_CMD_OFFSET, 1); if (ret) return ret; ret = mxt_read_messages(mxt, 100, (void *) &t109_command, mxt_self_cap_command, (int *)&mxt_sigint_rx); if (ret) return ret; mxt_info(mxt->ctx, "Saving configuration"); ret = mxt_backup_config(mxt, BACKUPNV_COMMAND); if (ret) return ret; ret = mxt_reset_chip(mxt, false); if (ret) return ret; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Write LENGTH /// \return #mxt_rc static int mxt_t68_write_length(struct t68_ctx *ctx, uint8_t length) { mxt_dbg(ctx->lc, "Writing LENGTH=%u", length); return mxt_write_register(ctx->mxt, &length, ctx->t68_addr + T68_LENGTH, 1); }