int check_tsp_type(int tx, int rx) { struct CMCS_CH_INFO *ch = (struct CMCS_CH_INFO *)&ts_cmcs->cmcs.ch; int last_rx_ch = (int)ch->rx_num - 1; int last_tx_ch = (int)ch->tx_num - 1; if ((rx > last_rx_ch) || (rx < 0) || (tx > last_tx_ch) || (tx < 0)) { tsp_warn("TSP channel is not correct!! (%d * %d)\n", tx, rx); return TSP_CH_UNKNOWN; } if (ch->key_rx) { // Key on RX channel if (rx == last_rx_ch) { if ((tx == ch->key1) || (tx == ch->key2) || (tx == ch->key3) || (tx == ch->key4) || (tx == ch->key5)) return TSP_CH_KEY; else return TSP_CH_UNUSED; } } // Key on TX channel else { if (tx == last_tx_ch) { if ((rx == ch->key1) || (rx == ch->key2) || (rx == ch->key3) || (rx == ch->key4) || (rx == ch->key5)) return TSP_CH_KEY; else return TSP_CH_UNUSED; } } return TSP_CH_SCREEN; }
void timer_handler(unsigned long data) { int event_ms; int curr_ms; if (get_event_mode) { if ((ts_data->status.power == 1) && (ts_data->status.update != 1)) { ktime_get_ts(&t_current); curr_ms = t_current.tv_sec * 1000 + t_current.tv_nsec / 1000000; event_ms = t_event.tv_sec * 1000 + t_event.tv_nsec / 1000000; tsp_verb("event_ms %d, current: %d\n", event_ms, curr_ms); if (ts_data->status.calib == 1) { if (curr_ms - event_ms >= 2000) { // 2second ts_data->status.calib = 0; tsp_debug("calibration timeout over 3sec\n"); schedule_delayed_work(&work_reset_check, 0); ktime_get_ts(&t_event); } } #if IST30XX_NOISE_MODE else if (curr_ms - event_ms >= 5000) { // 5second tsp_warn("idle timeout over 5sec\n"); schedule_delayed_work(&work_reset_check, 0); } #endif // IST30XX_NOISE_MODE } } mod_timer(&idle_timer, get_jiffies_64() + EVENT_TIMER_INTERVAL); }
int ist30xx_get_cmcs_info(const u8 *buf, const u32 size) { int ret; cmcs_ready = CMCS_NOT_READY; ret = ist30xx_parse_cmcs_bin(buf, size); if (unlikely(ret != TAGS_PARSE_OK)) tsp_warn("Cannot find tags of CMCS, make a bin by 'cmcs2bin.exe'\n"); return ret; }
static int check_report_data(struct ist30xx_data *data, int finger_counts, int key_counts) { int i, j; bool valid_id; finger_info *fingers = (finger_info *)data->fingers; finger_info *prev_fingers = (finger_info *)data->prev_fingers; /* current finger info */ for (i = 0; i < finger_counts; i++) { if ((fingers[i].bit_field.id == 0) || (fingers[i].bit_field.id > ist30xx_tsp_info.finger_num) || (fingers[i].bit_field.x > IST30XX_MAX_X) || (fingers[i].bit_field.y > IST30XX_MAX_Y)) { tsp_warn("Invalid touch data - %d: %d(%d, %d)\n", i, fingers[i].bit_field.id, fingers[i].bit_field.x, fingers[i].bit_field.y); fingers[i].bit_field.id = 0; return -EPERM; } } /* previous finger info */ if (data->num_fingers >= finger_counts) { for (i = 0; i < ist30xx_tsp_info.finger_num; i++) { // prev_fingers if (prev_fingers[i].bit_field.id != 0 && (prev_fingers[i].bit_field.udmg & PRESS_MSG_MASK)) { valid_id = false; for (j = 0; j < ist30xx_tsp_info.finger_num; j++) { // fingers if ((prev_fingers[i].bit_field.id) == (fingers[j].bit_field.id)) { valid_id = true; break; } } if (valid_id == false) release_finger(&prev_fingers[i]); } } } return 0; }
int ist30xx_load_cmcs_binary(struct ist30xx_data *data) { int i, ret; struct ist30xx_config_info *info = data->pdata->config_array; const struct firmware *req_cmcs_bin = NULL; for (i = 0; i < data->pdata->config_array_size; i++) { if (data->tsp_type == info[i].tsp_type) break; } /* If no corresponding tsp firmware is found, just use the default one */ if (i >= data->pdata->config_array_size) { tsp_warn("No corresponding TSP firmware found, use the default one(%x)\n", data->tsp_type); i = 0; } else { tsp_info("TSP vendor: %s(%x)\n", info[i].tsp_name, data->tsp_type); } ret = request_firmware(&req_cmcs_bin, info[i].cmcs_name, &data->client->dev); if (unlikely(ret)) { tsp_err("Cannot load CMCS binary file: %s\n", info[i].cmcs_name); return ret; } data->cmcs_bin = kmalloc(req_cmcs_bin->size, GFP_KERNEL); if (unlikely(!data->cmcs_bin)) { tsp_err("Cannot allocate memory for CMCS binary.\n"); release_firmware(req_cmcs_bin); return -ENOMEM; } memcpy(data->cmcs_bin, req_cmcs_bin->data, req_cmcs_bin->size); data->cmcs_bin_size = (u32)req_cmcs_bin->size; tsp_info("CMCS binary [%s] loaded successfully.\n", info[i].cmcs_name); release_firmware(req_cmcs_bin); return 0; }
int ist30xx_cmcs_test(const u8 *buf, int size) { int ret; int len; u32 chksum = 0; u32 *buf32; struct i2c_client *client = (struct i2c_client *)ts_data->client; CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; tsp_info("*** CM/CS test ***\n"); tsp_info(" mode: 0x%x, baseline(screen: %d, key: %d)\n", cmcs->cmd.mode, cmcs->cmd.base_screen, cmcs->cmd.base_key); tsp_info(" start_cp (cm: %d, cs: %d), vcmp (cm: %d, cs: %d)\n", cmcs->cmd.start_cp_cm, cmcs->cmd.start_cp_cs, cmcs->cmd.vcmp_cm, cmcs->cmd.vcmp_cs); ist30xx_disable_irq(ts_data); ist30xx_reset(false); ret = ist30xx_cmd_reg(client, CMD_ENTER_REG_ACCESS); cmcs_next_step(ret); /* Set sensor register */ buf32 = ts_cmcs->buf_sensor; ret = ist30xx_set_cmcs_sensor(client, cmcs, buf32); cmcs_next_step(ret); /* Set command */ ret = ist30xx_set_cmcs_cmd(client, cmcs); cmcs_next_step(ret); ret = ist30xx_cmd_reg(client, CMD_EXIT_REG_ACCESS); cmcs_next_step(ret); /* Load cmcs test code */ ret = ist30xx_write_cmd(client, CMD_EXEC_MEM_CODE, 0); cmcs_next_step(ret); buf32 = (u32 *)ts_cmcs->buf_cmcs; len = cmcs->cmd.cmcs_size / IST30XX_DATA_LEN; tsp_verb("%08x %08x %08x %08x\n", buf32[0], buf32[1], buf32[2], buf32[3]); ret = ist30xx_write_buf(client, len, buf32, len); cmcs_next_step(ret); /* Check checksum */ ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum); cmcs_next_step(ret); if (chksum != IST30XX_CMCS_LOAD_END) goto end; tsp_info("CM/CS code ready!!\n"); /* Check checksum */ ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum); cmcs_next_step(ret); tsp_info("CM/CS code chksum: %08x, %08x\n", chksum, cmcs->cmcs_chksum); ist30xx_enable_irq(ts_data); /* Wait CMCS test result */ if (ist30xx_calib_wait() == 1) tsp_info("CM/CS test OK.\n"); else tsp_info("CM/CS test fail.\n"); ist30xx_disable_irq(ts_data); /* Read CM/CS data*/ if (ENABLE_CM_MODE(cmcs->cmd.mode)) { /* Read CM data */ memset(ts_cmcs_buf->cm, 0, sizeof(ts_cmcs_buf->cm)); ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cm); cmcs_next_step(ret); ret = ist30xx_apply_cmcs_slope(cmcs, ts_cmcs_buf); } if (ENABLE_CS_MODE(cmcs->cmd.mode)) { /* Read CS0 data */ memset(ts_cmcs_buf->cs0, 0, sizeof(ts_cmcs_buf->cs0)); memset(ts_cmcs_buf->cs1, 0, sizeof(ts_cmcs_buf->cs1)); ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs0); cmcs_next_step(ret); /* Read CS1 data */ ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs1); cmcs_next_step(ret); } ist30xx_reset(false); ist30xx_start(ts_data); cmcs_ready = CMCS_READY; end: if (unlikely(ret)) { tsp_warn("CM/CS test Fail!, ret=%d\n", ret); } else if (unlikely(chksum != cmcs->cmcs_chksum)) { tsp_warn("Error CheckSum: %x(%x)\n", chksum, cmcs->cmcs_chksum); ret = -ENOEXEC; } ist30xx_enable_irq(ts_data); return ret; }
static irqreturn_t ist30xx_irq_thread(int irq, void *ptr) { int i, ret; int key_cnt, finger_cnt, read_cnt; struct ist30xx_data *data = ptr; u32 msg[IST30XX_MAX_MT_FINGERS]; bool unknown_idle = false; #if IST30XX_TRACKING_MODE u32 ms; #endif if (!data->irq_enabled) return IRQ_HANDLED; memset(msg, 0, sizeof(msg)); ret = ist30xx_get_position(data->client, msg, 1); if (ret) goto irq_err; tsp_verb("intr msg: 0x%08x\n", *msg); if (msg[0] == 0) return IRQ_HANDLED; #if IST30XX_EVENT_MODE if ((data->status.update != 1) && (data->status.calib != 1)) ktime_get_ts(&t_event); #endif #if IST30XX_TRACKING_MODE ms = t_event.tv_sec * 1000 + t_event.tv_nsec / 1000000; ist30xx_put_track(ms, msg[0]); #endif #if IST30XX_NOISE_MODE if (get_event_mode) { if ((msg[0] & 0xFFFF0000) == IST30XX_IDLE_STATUS) { if (msg[0] & IDLE_ALGORITHM_MODE) return IRQ_HANDLED; for (i = 0; i < IST30XX_MAX_MT_FINGERS; i++) { if (data->prev_fingers[i].bit_field.id == 0) continue; if (data->prev_fingers[i].bit_field.udmg & PRESS_MSG_MASK) { tsp_warn("prev_fingers: %08x\n", data->prev_fingers[i].full_field); release_finger(&data->prev_fingers[i]); unknown_idle = true; } } for (i = 0; i < data->num_keys; i++) { if (data->prev_keys[i].bit_field.id == 0) continue; if (data->prev_keys[i].bit_field.w == PRESS_MSG_KEY) { tsp_warn("prev_keys: %08x\n", data->prev_keys[i].full_field); release_key(&data->prev_keys[i], RELEASE_KEY); unknown_idle = true; } } if (unknown_idle) { schedule_delayed_work(&work_reset_check, 0); tsp_warn("Find unknown pressure\n"); } return IRQ_HANDLED; } } #endif // IST30XX_NOISE_MODE if ((msg[0] & CALIB_MSG_MASK) == CALIB_MSG_VALID) { data->status.calib_msg = msg[0]; tsp_info("calib status: 0x%08x\n", data->status.calib_msg); return IRQ_HANDLED; } for (i = 0; i < IST30XX_MAX_MT_FINGERS; i++) data->fingers[i].full_field = 0; key_cnt = 0; finger_cnt = 1; read_cnt = 1; data->fingers[0].full_field = msg[0]; if (data->fingers[0].bit_field.udmg & MULTI_MSG_MASK) { key_cnt = data->fingers[0].bit_field.x; finger_cnt = data->fingers[0].bit_field.y; read_cnt = finger_cnt + key_cnt; if (finger_cnt > ist30xx_tsp_info.finger_num || key_cnt > ist30xx_tkey_info.key_num) { tsp_warn("Invalid touch count - finger: %d(%d), key: %d(%d)\n", finger_cnt, ist30xx_tsp_info.finger_num, key_cnt, ist30xx_tkey_info.key_num); goto irq_err; } #if I2C_BURST_MODE ret = ist30xx_get_position(data->client, msg, read_cnt); if (ret) goto irq_err; for (i = 0; i < read_cnt; i++) data->fingers[i].full_field = msg[i]; #else for (i = 0; i < read_cnt; i++) { ret = ist30xx_get_position(data->client, &msg[i], 1); if (ret) goto irq_err; data->fingers[i].full_field = msg[i]; } #endif // I2C_BURST_MODE for (i = 0; i < read_cnt; i++) tsp_verb("intr msg[%d]: 0x%08x\n", i, msg[i]); #if IST30XX_TRACKING_MODE for (i = 0; i < read_cnt; i++) ist30xx_put_track(ms, msg[i]); #endif } if (check_report_data(data, finger_cnt, key_cnt)) return IRQ_HANDLED; if (read_cnt > 0) report_input_data(data, finger_cnt, key_cnt); return IRQ_HANDLED; irq_err: tsp_err("intr msg[0]: 0x%08x, ret: %d\n", msg[0], ret); ist30xx_request_reset(); return IRQ_HANDLED; }
static void report_input_data(struct ist30xx_data *data, int finger_counts, int key_counts) { int i, press, count; finger_info *fingers = (finger_info *)data->fingers; memset(data->prev_fingers, 0, sizeof(data->prev_fingers)); #if 1 // for LGE scenario if (finger_counts) { for (i = 0; i < 5; i++) { //tsp_debug("finger[%d]: %08x\n", i, data->prev_keys[i].full_field); if (data->prev_keys[i].bit_field.id ==0) continue; if (data->prev_keys[i].bit_field.w == PRESS_MSG_KEY) { tsp_warn("key cancel: %08x\n", data->prev_keys[i].full_field); release_key(&data->prev_keys[i], CANCEL_KEY); } } } #endif for (i = 0, count = 0; i < finger_counts; i++) { press = fingers[i].bit_field.udmg & PRESS_MSG_MASK; //print_tsp_event(&fingers[i]); #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0)) input_mt_slot(data->input_dev, fingers[i].bit_field.id - 1); input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, (press ? true : false)); if (press) { input_report_abs(data->input_dev, ABS_MT_POSITION_X, fingers[i].bit_field.x); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, fingers[i].bit_field.y); input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, fingers[i].bit_field.w); } printk("[ TSP ] id : %2d, press : %2d , x : %3d, y :%3d, width : %3d\n", fingers[i].bit_field.id - 1, press, fingers[i].bit_field.x, fingers[i].bit_field.y, fingers[i].bit_field.w); #else input_report_abs(data->input_dev, ABS_MT_POSITION_X, fingers[i].bit_field.x); input_report_abs(data->input_dev, ABS_MT_POSITION_Y, fingers[i].bit_field.y); input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, press); input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, fingers[i].bit_field.w); input_mt_sync(data->input_dev); #endif // (LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0) data->prev_fingers[i] = fingers[i]; count++; } #if IST30XX_USE_KEY for (i = finger_counts; i < finger_counts + key_counts; i++) { key_id = fingers[i].bit_field.id; key_press = (fingers[i].bit_field.w == PRESS_MSG_KEY) ? 1 : 0; if (finger_on_screen()) { // Ignore touch key tsp_warn("Ignore key id: %d\n", key_id); continue; } tsp_debug("key(%08x) id: %d, press: %d, sensitivity: %d\n", fingers[i].full_field, key_id, key_press, fingers[i].bit_field.y); input_report_key(data->input_dev, ist30xx_key_code[key_id], key_press); data->prev_keys[key_id-1] = fingers[i]; count++; } #endif // IST30XX_USE_KEY if (count > 0) input_sync(data->input_dev); data->num_fingers = finger_counts; ist30xx_error_cnt = 0; }