int ist30xx_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int msg_num, u8 *cmd_buf) { int ret = 0; int idx = msg_num - 1; int size = msgs[idx].len; u8 *msg_buf = NULL; u8 *pbuf = NULL; int trans_size, max_size = 0; if (msg_num == WRITE_CMD_MSG_LEN) max_size = I2C_MAX_WRITE_SIZE; else if (msg_num == READ_CMD_MSG_LEN) max_size = I2C_MAX_READ_SIZE; if (unlikely(max_size == 0)) { tsp_err("%s() : transaction size(%d)\n", __func__, max_size); return -EINVAL; } if (msg_num == WRITE_CMD_MSG_LEN) { msg_buf = kmalloc(max_size + IST30XX_ADDR_LEN, GFP_KERNEL); if (!msg_buf) return -ENOMEM; memcpy(msg_buf, cmd_buf, IST30XX_ADDR_LEN); pbuf = msgs[idx].buf; } while (size > 0) { trans_size = (size >= max_size ? max_size : size); msgs[idx].len = trans_size; if (msg_num == WRITE_CMD_MSG_LEN) { memcpy(&msg_buf[IST30XX_ADDR_LEN], pbuf, trans_size); msgs[idx].buf = msg_buf; msgs[idx].len += IST30XX_ADDR_LEN; } ret = i2c_transfer(adap, msgs, msg_num); if (unlikely(ret != msg_num)) { tsp_err("%s() : i2c_transfer failed(%d), num=%d\n", __func__, ret, msg_num); break; } if (msg_num == WRITE_CMD_MSG_LEN) pbuf += trans_size; else msgs[idx].buf += trans_size; size -= trans_size; } if (msg_num == WRITE_CMD_MSG_LEN) kfree(msg_buf); return ret; }
int ist30xx_ts_on(void) { #if 1 ist30xx_ldo_power_on(ts_data, true); msleep(50); return 0; #else // struct ist30xx_ts_device *dev = NULL; int ret = 0; // dev = &ist30xx_ts_dev; ret = ts_data->power(ON); tsp_info("ist30xx_ts_on\n"); if(ret < 0) { tsp_err("ist30xx_ts_on power on failed\n"); goto err_power_failed; } ts_data->status.power = 1; msleep(30); err_power_failed: return ret; #endif }
void print_tsp_event(finger_info *finger) { int idx = finger->bit_field.id - 1; int press = finger->bit_field.udmg & PRESS_MSG_MASK; if ( idx < 0 ) { tsp_err("finger idx err! idx value : %d\n", idx); return; } if (press == PRESS_MSG_MASK) { if (tsp_touched[idx] == 0) { // touch down tsp_info("%s - %d (%d, %d)\n", TOUCH_DOWN_MESSAGE, finger->bit_field.id, finger->bit_field.x, finger->bit_field.y); tsp_touched[idx] = 1; } else { // touch move tsp_debug("%s %d (%d, %d)\n", TOUCH_MOVE_MESSAGE, finger->bit_field.id, finger->bit_field.x, finger->bit_field.y); } } else { if (tsp_touched[idx] == 1) { // touch up tsp_info("%s - %d (%d, %d)\n", TOUCH_UP_MESSAGE, finger->bit_field.id, finger->bit_field.x, finger->bit_field.y); tsp_touched[idx] = 0; } } }
int ist30xx_ts_off(void) { #if 1 ist30xx_ldo_power_on(ts_data, false); msleep(20); return 0; #else // struct ist30xx_ts_device *dev = NULL; int ret = 0; // dev = &ist30xx_ts_dev; ret = ts_data->power(OFF); tsp_info("ist30xx_ts_off\n"); if(ret < 0) { tsp_err("ist30xx_ts_off power off failed\n"); goto err_power_failed; } ts_data->status.power = 0; msleep(10); err_power_failed: return ret; #endif }
int ist30xx_init_tracking_sysfs(void) { /* /sys/class/touch/tracking */ ist30xx_tracking_dev = device_create(ist30xx_class, NULL, 0, NULL, "tracking"); /* /sys/class/touch/tracking/... */ if (sysfs_create_group(&ist30xx_tracking_dev->kobj, &tracking_attr_group)) tsp_err("[ TSP ] Failed to create sysfs group(%s)!\n", "tracking"); ist30xx_tracking_init(); 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_init_cmcs_sysfs(void) { /* /sys/class/touch/cmcs */ ist30xx_cmcs_dev = device_create(ist30xx_class, NULL, 0, NULL, "cmcs"); /* /sys/class/touch/cmcs/... */ if (unlikely(sysfs_create_group(&ist30xx_cmcs_dev->kobj, &cmcs_attr_group))) tsp_err("Failed to create sysfs group(%s)!\n", "cmcs"); #if IST30XX_INTERNAL_CMCS_BIN ts_cmcs_bin = (u8 *)ist30xxb_cmcs; ts_cmcs_bin_size = sizeof(ist30xxb_cmcs); ist30xx_get_cmcs_info(ts_cmcs_bin, ts_cmcs_bin_size); #endif return 0; }
int ist30xx_get_position(struct i2c_client *client, u32 *buf, u16 len) { int ret, i; pos_msg[0].addr = client->addr; pos_msg[1].addr = client->addr; pos_msg[1].len = len * IST30XX_DATA_LEN, pos_msg[1].buf = (u8 *)buf, ret = i2c_transfer(client->adapter, pos_msg, READ_CMD_MSG_LEN); if (ret != READ_CMD_MSG_LEN) { tsp_err("%s: i2c failed (%d)\n", __func__, ret); return -EIO; } for (i = 0; i < len; i++) buf[i] = cpu_to_be32(buf[i]); return 0; }
int ist30xx_init_cmcs_sysfs(struct ist30xx_data *data) { /* /sys/class/touch/cmcs */ data->cmcs_dev = device_create(data->ist30xx_class, NULL, 0, data, "cmcs"); /* /sys/class/touch/cmcs/... */ if (unlikely(sysfs_create_group(&data->cmcs_dev->kobj, &cmcs_attr_group))) tsp_err("Failed to create sysfs group(%s)!\n", "cmcs"); data->cmcs_bin = NULL; data->cmcs_bin_size = 0; data->cmcs = (CMCS_BIN_INFO *)&data->ist30xx_cmcs_bin; data->cmcs_buf = (CMCS_BUF *)&data->ist30xx_cmcs_buf; data->cmcs_ready = CMCS_NOT_READY; return 0; }
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 int __devinit ist30xx_probe(struct i2c_client * client, const struct i2c_device_id * id) { int ret; struct ist30xx_data *data; struct input_dev *input_dev; #if 0 /* [email protected] */ struct touch_platform_data *ts_pdata; // struct ist30xx_ts_device *dev; ts_pdata = client->dev.platform_data; // dev = &ist30xx_ts_dev; /* [email protected] */ #endif tsp_info("\n%s(), the i2c addr=0x%x \n", __func__, client->addr); /* dev->power = ts_pdata->power; dev->num_irq = ts_pdata->irq; dev->sda_gpio = ts_pdata->sda; dev->scl_gpio = ts_pdata->scl;*/ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { tsp_debug("failed to i2c functionality check"); ret = -ENODEV; goto err_check_functionality_failed; } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->client = client; if(client->dev.of_node) { data->pdata = devm_kzalloc(&client->dev, sizeof(struct ist30xx_tsi_platform_data), GFP_KERNEL); if(!data->pdata) { tsp_debug("failed to allocate platform_data"); return -ENOMEM; } ret = ist30xx_parse_dt(&client->dev, data->pdata); if(ret) { tsp_debug("device tree parsing failed"); return ret; } } else { data->pdata = client->dev.platform_data; } ret = ist30xx_regulator_configure(data, true); if (ret < 0) { tsp_debug("Failed to configure regulators"); } ret = ist30xx_ldo_power_on(data, true); if (ret < 0) { tsp_debug("Failed to power on"); } input_dev = input_allocate_device(); if (!input_dev) { ret = -ENOMEM; tsp_err("%s(), input_allocate_device failed (%d)\n", __func__, ret); goto err_alloc_dev; } #if 0 DMSG("[ TSP ] irq : %d, scl : %d, sda : %d\n", client->irq, ts_pdata->scl, ts_pdata->sda); #endif data->num_fingers = IST30XX_MAX_MT_FINGERS; data->num_keys = IST30XX_MAX_MT_FINGERS; data->irq_enabled = 1; data->client = client; data->input_dev = input_dev; #if 0 /* [email protected] */ data->power = ts_pdata->power; /* [email protected] */ #endif i2c_set_clientdata(client, data); #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0)) input_mt_init_slots(input_dev, IST30XX_MAX_MT_FINGERS); #endif input_dev->name = "ist30xx_ts_input"; input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; set_bit(EV_ABS, input_dev->evbit); #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0)) set_bit(INPUT_PROP_DIRECT, input_dev->propbit); #endif input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, IST30XX_MAX_X, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, IST30XX_MAX_Y, 0, 0); #if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 0, 0)) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, IST30XX_MAX_W, 0, 0); #else input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, IST30XX_MAX_Z, 0, 0); input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, IST30XX_MAX_W, 0, 0); #endif #if IST30XX_USE_KEY { int i; set_bit(EV_KEY, input_dev->evbit); set_bit(EV_SYN, input_dev->evbit); for (i = 1; i < ARRAY_SIZE(ist30xx_key_code); i++) set_bit(ist30xx_key_code[i], input_dev->keybit); } #endif input_set_drvdata(input_dev, data); ret = input_register_device(input_dev); if (ret) { input_free_device(input_dev); goto err_reg_dev; } #if defined(CONFIG_FB) data->fb_notif.notifier_call = fb_notifier_callback; ret = fb_register_client(&data->fb_notif); if(ret) tsp_debug("Unable to register fb_notifier \n"); else tsp_debug("Register fb_notifier \n"); #elif defined(CONFIG_HAS_EARLYSUSPEND) data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; data->early_suspend.suspend = ist30xx_early_suspend; data->early_suspend.resume = ist30xx_late_resume; register_early_suspend(&data->early_suspend); #endif ts_data = data; ret = ist30xx_init_system(); if (ret) { dev_err(&client->dev, "chip initialization failed\n"); goto err_init_drv; } ret = ist30xx_init_update_sysfs(); if (ret) goto err_init_drv; #if IST30XX_DEBUG ret = ist30xx_init_misc_sysfs(); if (ret) goto err_init_drv; #endif # if IST30XX_FACTORY_TEST ret = ist30xx_init_factory_sysfs(); if (ret) goto err_init_drv; #endif #if IST30XX_TRACKING_MODE ret = ist30xx_init_tracking_sysfs(); if (ret) goto err_init_drv; #endif ret = request_threaded_irq(client->irq, NULL, ist30xx_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "ist30xx_ts", data); if (ret) goto err_irq; ist30xx_disable_irq(data); #if IST30XX_INTERNAL_BIN # if IST30XX_UPDATE_BY_WORKQUEUE INIT_DELAYED_WORK(&work_fw_update, fw_update_func); schedule_delayed_work(&work_fw_update, IST30XX_UPDATE_DELAY); # else ret = ist30xx_auto_bin_update(data); if (ret < 0) goto err_irq; # endif #endif // IST30XX_INTERNAL_BIN ret = ist30xx_get_info(data); tsp_info("Get info: %s\n", (ret == 0 ? "success" : "fail")); INIT_DELAYED_WORK(&work_reset_check, reset_work_func); #if IRQ_THREAD_WORK_QUEUE INIT_WORK(&work_irq_thread, irq_thread_func); #endif #if IST30XX_DETECT_TA ist30xx_ta_status = 0; #endif #if IST30XX_EVENT_MODE init_timer(&idle_timer); idle_timer.function = timer_handler; idle_timer.expires = jiffies_64 + (EVENT_TIMER_INTERVAL); mod_timer(&idle_timer, get_jiffies_64() + EVENT_TIMER_INTERVAL); ktime_get_ts(&t_event); #endif ist30xx_initialized = 1; return 0; err_irq: ist30xx_disable_irq(data); free_irq(client->irq, data); err_init_drv: #if IST30XX_EVENT_MODE get_event_mode = false; #endif tsp_err("Error, ist30xx init driver\n"); // ist30xx_power_off(); ist30xx_ts_off(); input_unregister_device(input_dev); return 0; err_reg_dev: err_alloc_dev: tsp_err("Error, ist30xx mem free\n"); kfree(data); err_check_functionality_failed: return 0; }
ssize_t ist30xx_cmcs_test_all_show(struct device *dev, struct device_attribute *attr, char *buf) { int ret; char* msg = NULL; struct ist30xx_data *data = dev_get_drvdata(dev); CMCS_INFO *cmcs = (CMCS_INFO *)&data->cmcs->cmcs; msg = kzalloc(sizeof(char) * 4096, GFP_KERNEL); if (!msg) { tsp_err("Memory allocation failed\n"); return 0; } /* CMCS Binary */ ret = ist30xx_load_cmcs_binary(data); if (unlikely(ret)) { kfree(msg); return sprintf(buf, "Binary loaded failed(%d).\n", data->cmcs_bin_size); } ist30xx_get_cmcs_info(data, data->cmcs_bin, data->cmcs_bin_size); mutex_lock(&data->ist30xx_mutex); ret = ist30xx_cmcs_test(data, data->cmcs_bin, data->cmcs_bin_size); mutex_unlock(&data->ist30xx_mutex); if (likely(data->cmcs_bin != NULL)) { kfree(data->cmcs_bin); data->cmcs_bin = NULL; data->cmcs_bin_size = 0; } if (ret == 0) { tsp_debug("CMCS Binary test passed!\n"); } else { kfree(msg); return sprintf(buf, "CMCS Binary test failed!\n"); } if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) { kfree(msg); return sprintf(buf, "CMCS not enabled!\n"); } /* CM Result */ memset(msg, 0, sizeof(msg)); ret = print_cm_result(data, msg); if (strncmp(msg, "OK\n", strlen("OK\n")) == 0) { tsp_debug("CM result test passed!\n"); } else { goto out; } /* CM Slope 0 Result */ memset(msg, 0, sizeof(msg)); ret = print_cm_slope_result(data, CMCS_FLAG_CM_SLOPE0, data->cmcs_buf->slope0, msg); if (strncmp(msg, "OK\n", strlen("OK\n")) == 0) { tsp_debug("CM Slope 0 test passed!\n"); } else { goto out; } /* CM Slope 1 Result */ memset(msg, 0, sizeof(msg)); ret = print_cm_slope_result(data, CMCS_FLAG_CM_SLOPE1, data->cmcs_buf->slope1, msg); if (strncmp(msg, "OK\n", strlen("OK\n")) == 0) { tsp_debug("CM Slope 1 test passed!\n"); } else { goto out; } /* CS 0 Result */ memset(msg, 0, sizeof(msg)); ret = print_cs_result(data, data->cmcs_buf->cs0, msg, 0); if (strncmp(msg, "OK\n", strlen("OK\n")) == 0) { tsp_debug("CS 0 test passed!\n"); } else { goto out; } /* CS 1 Result */ memset(msg, 0, sizeof(msg)); ret = print_cs_result(data, data->cmcs_buf->cs1, msg, 1); if (strncmp(msg, "OK\n", strlen("OK\n")) == 0) { tsp_debug("CS 1 test passed!\n"); } else { goto out; } out: ret = sprintf(buf, "%s", msg); kfree(msg); return ret; }