blob: ad9ba7177be850e043ea661d2bcc2c4fc118a9b6 [file] [log] [blame]
/* drivers/input/touchscreen/sec_ts_fn.c
*
* Copyright (C) 2015 Samsung Electronics Co., Ltd.
* http://www.samsungsemi.com/
*
* Core file for Samsung TSC driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "sec_ts.h"
#include "sec_ts_fac_spec.h"
static void fw_update(void *device_data);
static void get_fw_ver_bin(void *device_data);
static void get_fw_ver_ic(void *device_data);
static void get_config_ver(void *device_data);
#ifdef PAT_CONTROL
static void get_pat_information(void *device_data);
static void set_external_factory(void *device_data);
#endif
static void get_threshold(void *device_data);
static void module_off_master(void *device_data);
static void module_on_master(void *device_data);
static void get_chip_vendor(void *device_data);
static void get_chip_name(void *device_data);
static void set_mis_cal_spec(void *device_data);
static void get_mis_cal_info(void *device_data);
static void get_wet_mode(void *device_data);
static void get_x_num(void *device_data);
static void get_y_num(void *device_data);
static void get_x_cross_routing(void *device_data);
static void get_y_cross_routing(void *device_data);
static void get_checksum_data(void *device_data);
static void run_reference_read(void *device_data);
static void run_reference_read_all(void *device_data);
static void get_reference(void *device_data);
static void run_rawcap_read(void *device_data);
static void run_rawcap_read_all(void *device_data);
static void run_rawcap_high_freq_read_all(void *device_data);
static void get_rawcap(void *device_data);
static void run_rawcap_gap_read_all(void *device_data);
static void run_delta_read(void *device_data);
static void run_delta_read_all(void *device_data);
static void get_delta(void *device_data);
static void run_rawdata_stdev_read(void *device_data);
static void run_rawdata_p2p_read_all(void *device_data);
static void run_rawdata_read_type(void *device_data);
static void run_rawdata_read_all(void *device_data);
static void run_self_reference_read(void *device_data);
static void run_self_reference_read_all(void *device_data);
static void run_self_rawcap_read(void *device_data);
static void run_self_rawcap_read_all(void *device_data);
static void run_self_rawcap_gap_read_all(void *device_data);
static void run_self_delta_read(void *device_data);
static void run_self_delta_read_all(void *device_data);
static void run_force_calibration(void *device_data);
static void get_force_calibration(void *device_data);
#ifdef USE_PRESSURE_SENSOR
static void run_force_pressure_calibration(void *device_data);
static void set_pressure_test_mode(void *device_data);
static void run_pressure_filtered_strength_read_all(void *device_data);
static void run_pressure_strength_read_all(void *device_data);
static void run_pressure_rawdata_read_all(void *device_data);
static void run_pressure_offset_read_all(void *device_data);
static void set_pressure_strength(void *device_data);
static void set_pressure_rawdata(void *device_data);
static void set_pressure_data_index(void *device_data);
static void get_pressure_strength(void *device_data);
static void get_pressure_rawdata(void *device_data);
static void get_pressure_data_index(void *device_data);
static void set_pressure_strength_clear(void *device_data);
static void get_pressure_threshold(void *device_data);
static void set_pressure_user_level(void *device_data);
static void get_pressure_user_level(void *device_data);
#endif
static void run_fs_cal_pre_press(void *device_data);
static void run_fs_cal_get_data(void *device_data);
static void run_fs_cal_post_press(void *device_data);
static void enable_fs_cal_table(void *device_data);
static void enable_coordinate_report(void *device_data);
static void enable_gain_limit(void *device_data);
static void run_trx_short_test(void *device_data);
static void set_tsp_test_result(void *device_data);
static void get_tsp_test_result(void *device_data);
static void increase_disassemble_count(void *device_data);
static void get_disassemble_count(void *device_data);
static void glove_mode(void *device_data);
static void clear_cover_mode(void *device_data);
static void dead_zone_enable(void *device_data);
static void drawing_test_enable(void *device_data);
static void set_lowpower_mode(void *device_data);
static void set_wirelesscharger_mode(void *device_data);
static void spay_enable(void *device_data);
static void set_aod_rect(void *device_data);
static void get_aod_rect(void *device_data);
static void aod_enable(void *device_data);
static void set_grip_data(void *device_data);
static void dex_enable(void *device_data);
static void brush_enable(void *device_data);
static void force_touch_active(void *device_data);
static void set_touchable_area(void *device_data);
static void set_log_level(void *device_data);
static void debug(void *device_data);
static void set_touch_mode(void *device_data);
static void not_support_cmd(void *device_data);
static void set_palm_detection_enable(void *device_data);
static void set_grip_detection_enable(void *device_data);
static void set_wet_mode_enable(void *device_data);
static void set_noise_mode_enable(void *device_data);
static void set_continuous_report_enable(void *device_data);
static void set_charger_nb_enable(void *device_data);
static void set_print_format(void *device_data);
static void run_cal_check(void *device_data);
static struct sec_cmd sec_cmds[] = {
{SEC_CMD("fw_update", fw_update),},
{SEC_CMD("get_fw_ver_bin", get_fw_ver_bin),},
{SEC_CMD("get_fw_ver_ic", get_fw_ver_ic),},
{SEC_CMD("get_config_ver", get_config_ver),},
#ifdef PAT_CONTROL
{SEC_CMD("get_pat_information", get_pat_information),},
{SEC_CMD("set_external_factory", set_external_factory),},
#endif
{SEC_CMD("get_threshold", get_threshold),},
{SEC_CMD("module_off_master", module_off_master),},
{SEC_CMD("module_on_master", module_on_master),},
{SEC_CMD("get_chip_vendor", get_chip_vendor),},
{SEC_CMD("get_chip_name", get_chip_name),},
{SEC_CMD("set_mis_cal_spec", set_mis_cal_spec),},
{SEC_CMD("get_mis_cal_info", get_mis_cal_info),},
{SEC_CMD("get_wet_mode", get_wet_mode),},
{SEC_CMD("get_x_num", get_x_num),},
{SEC_CMD("get_y_num", get_y_num),},
{SEC_CMD("get_x_cross_routing", get_x_cross_routing),},
{SEC_CMD("get_y_cross_routing", get_y_cross_routing),},
{SEC_CMD("get_checksum_data", get_checksum_data),},
{SEC_CMD("run_reference_read", run_reference_read),},
{SEC_CMD("run_reference_read_all", run_reference_read_all),},
{SEC_CMD("get_reference", get_reference),},
{SEC_CMD("run_rawcap_read", run_rawcap_read),},
{SEC_CMD("run_rawcap_read_all", run_rawcap_read_all),},
{SEC_CMD("get_rawcap", get_rawcap),},
{SEC_CMD("run_rawcap_gap_read_all", run_rawcap_gap_read_all),},
{SEC_CMD("run_delta_read", run_delta_read),},
{SEC_CMD("run_delta_read_all", run_delta_read_all),},
{SEC_CMD("get_delta", get_delta),},
{SEC_CMD("run_rawdata_stdev_read", run_rawdata_stdev_read),},
{SEC_CMD("run_rawdata_p2p_read_all", run_rawdata_p2p_read_all),},
{SEC_CMD("run_rawdata_read_type", run_rawdata_read_type),},
{SEC_CMD("run_rawdata_read_all", run_rawdata_read_all),},
{SEC_CMD("run_self_reference_read", run_self_reference_read),},
{SEC_CMD("run_self_reference_read_all", run_self_reference_read_all),},
{SEC_CMD("run_self_rawcap_read", run_self_rawcap_read),},
{SEC_CMD("run_self_rawcap_read_all", run_self_rawcap_read_all),},
{SEC_CMD("run_self_rawcap_gap_read_all",
run_self_rawcap_gap_read_all),},
{SEC_CMD("run_rawcap_high_freq_read_all",
run_rawcap_high_freq_read_all),},
{SEC_CMD("run_self_delta_read", run_self_delta_read),},
{SEC_CMD("run_self_delta_read_all", run_self_delta_read_all),},
{SEC_CMD("run_force_calibration", run_force_calibration),},
{SEC_CMD("get_force_calibration", get_force_calibration),},
#ifdef USE_PRESSURE_SENSOR
{SEC_CMD("run_force_pressure_calibration",
run_force_pressure_calibration),},
{SEC_CMD("set_pressure_test_mode", set_pressure_test_mode),},
{SEC_CMD("run_pressure_filtered_strength_read_all",
run_pressure_filtered_strength_read_all),},
{SEC_CMD("run_pressure_strength_read_all",
run_pressure_strength_read_all),},
{SEC_CMD("run_pressure_rawdata_read_all",
run_pressure_rawdata_read_all),},
{SEC_CMD("run_pressure_offset_read_all",
run_pressure_offset_read_all),},
{SEC_CMD("set_pressure_strength", set_pressure_strength),},
{SEC_CMD("set_pressure_rawdata", set_pressure_rawdata),},
{SEC_CMD("set_pressure_data_index", set_pressure_data_index),},
{SEC_CMD("get_pressure_strength", get_pressure_strength),},
{SEC_CMD("get_pressure_rawdata", get_pressure_rawdata),},
{SEC_CMD("get_pressure_data_index", get_pressure_data_index),},
{SEC_CMD("set_pressure_strength_clear", set_pressure_strength_clear),},
{SEC_CMD("get_pressure_threshold", get_pressure_threshold),},
{SEC_CMD("set_pressure_user_level", set_pressure_user_level),},
{SEC_CMD("get_pressure_user_level", get_pressure_user_level),},
#endif
{SEC_CMD("run_fs_cal_pre_press", run_fs_cal_pre_press),},
{SEC_CMD("run_fs_cal_get_data", run_fs_cal_get_data),},
{SEC_CMD("run_fs_cal_post_press", run_fs_cal_post_press),},
{SEC_CMD("enable_fs_cal_table", enable_fs_cal_table),},
{SEC_CMD("enable_coordinate_report", enable_coordinate_report),},
{SEC_CMD("enable_gain_limit", enable_gain_limit),},
{SEC_CMD("run_trx_short_test", run_trx_short_test),},
{SEC_CMD("set_tsp_test_result", set_tsp_test_result),},
{SEC_CMD("get_tsp_test_result", get_tsp_test_result),},
{SEC_CMD("increase_disassemble_count", increase_disassemble_count),},
{SEC_CMD("get_disassemble_count", get_disassemble_count),},
{SEC_CMD("glove_mode", glove_mode),},
{SEC_CMD("clear_cover_mode", clear_cover_mode),},
{SEC_CMD("dead_zone_enable", dead_zone_enable),},
{SEC_CMD("drawing_test_enable", drawing_test_enable),},
{SEC_CMD("set_lowpower_mode", set_lowpower_mode),},
{SEC_CMD("set_wirelesscharger_mode", set_wirelesscharger_mode),},
{SEC_CMD("spay_enable", spay_enable),},
{SEC_CMD("set_aod_rect", set_aod_rect),},
{SEC_CMD("get_aod_rect", get_aod_rect),},
{SEC_CMD("aod_enable", aod_enable),},
{SEC_CMD("set_grip_data", set_grip_data),},
{SEC_CMD("dex_enable", dex_enable),},
{SEC_CMD("brush_enable", brush_enable),},
{SEC_CMD("force_touch_active", force_touch_active),},
{SEC_CMD("set_touchable_area", set_touchable_area),},
{SEC_CMD("set_log_level", set_log_level),},
{SEC_CMD("debug", debug),},
{SEC_CMD("set_touch_mode", set_touch_mode),},
{SEC_CMD("set_palm_detection_enable", set_palm_detection_enable),},
{SEC_CMD("set_grip_detection_enable", set_grip_detection_enable),},
{SEC_CMD("set_wet_mode_enable", set_wet_mode_enable),},
{SEC_CMD("set_noise_mode_enable", set_noise_mode_enable),},
{SEC_CMD("set_continuous_report_enable",
set_continuous_report_enable),},
{SEC_CMD("set_charger_nb_enable", set_charger_nb_enable),},
{SEC_CMD("set_print_format", set_print_format),},
{SEC_CMD("run_cal_check", run_cal_check),},
{SEC_CMD("not_support_cmd", not_support_cmd),},
};
static void set_palm_detection_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
u8 para = 0x0;
u8 ret = 0;
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
para = 0x1;
else if (sec->cmd_param[0] == 0)
para = 0x0;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_PALM_DETEC, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: write reg %#x para %#x failed, returned %i\n",
__func__, SEC_TS_CMD_SET_PALM_DETEC, para, ret);
goto err_out;
}
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void set_grip_detection_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
u8 para = 0x0;
u8 ret = 0;
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
para = 0x1F;
else if (sec->cmd_param[0] == 0)
para = 0x0;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_GRIP_DETEC, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: write reg %#x para %#x failed, returned %i\n",
__func__, SEC_TS_CMD_SET_GRIP_DETEC, para, ret);
goto err_out;
}
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void set_wet_mode_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
u8 para = 0x0;
u8 ret = 0;
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
para = 0x0;
else if (sec->cmd_param[0] == 0)
para = 0x1;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_WET_MODE, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: write reg %#x para %#x failed, returned %i\n",
__func__, SEC_TS_CMD_SET_WET_MODE, para, ret);
goto err_out;
}
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void set_noise_mode_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
u8 para = 0x0;
u8 ret = 0;
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
para = NOISE_MODE_DEFALUT;
else if (sec->cmd_param[0] == 0)
para = NOISE_MODE_OFF;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_NOISE_MODE, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: write reg %#x para %#x failed, returned %i\n",
__func__, SEC_TS_CMD_SET_NOISE_MODE, para, ret);
goto err_out;
}
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void set_continuous_report_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
u8 para = 0x0;
u8 ret = 0;
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
para = 0x1;
else if (sec->cmd_param[0] == 0)
para = 0x0;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_CONT_REPORT, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: write reg %#x para %#x failed, returned %i\n",
__func__, SEC_TS_CMD_SET_CONT_REPORT, para, ret);
goto err_out;
}
ts->use_default_mf = para;
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void set_charger_nb_enable(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[4] = { 0 };
input_info(true, &ts->client->dev,
"%s: %d\n", __func__, sec->cmd_param[0]);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (sec->cmd_param[0] == 1)
ts->ignore_charger_nb = 0;
else if (sec->cmd_param[0] == 0)
ts->ignore_charger_nb = 1;
else {
input_info(true, &ts->client->dev,
"%s: param error! param = %d\n",
__func__, sec->cmd_param[0]);
goto err_out;
}
scnprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err_out:
scnprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static ssize_t scrub_pos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[256] = { 0 };
#ifdef CONFIG_SAMSUNG_PRODUCT_SHIP
input_info(true, &ts->client->dev,
"%s: scrub_id: %d\n", __func__, ts->scrub_id);
#else
input_info(true, &ts->client->dev,
"%s: scrub_id: %d, X:%d, Y:%d\n", __func__,
ts->scrub_id, ts->scrub_x, ts->scrub_y);
#endif
snprintf(buff, sizeof(buff), "%d %d %d",
ts->scrub_id, ts->scrub_x, ts->scrub_y);
ts->scrub_x = 0;
ts->scrub_y = 0;
return snprintf(buf, PAGE_SIZE, "%s", buff);
}
static DEVICE_ATTR_RO(scrub_pos);
static ssize_t ito_check_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[256] = { 0 };
input_info(true, &ts->client->dev, "%s: %02X%02X%02X%02X\n", __func__,
ts->ito_test[0], ts->ito_test[1],
ts->ito_test[2], ts->ito_test[3]);
snprintf(buff, sizeof(buff), "%02X%02X%02X%02X",
ts->ito_test[0], ts->ito_test[1],
ts->ito_test[2], ts->ito_test[3]);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff);
}
static ssize_t raw_check_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
int ii, ret = 0;
char *buffer = NULL;
char temp[CMD_RESULT_WORD_LEN] = { 0 };
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
buffer = vzalloc(ts->rx_count * ts->tx_count * 6);
if (!buffer) {
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return -ENOMEM;
}
memset(buffer, 0x00, ts->rx_count * ts->tx_count * 6);
for (ii = 0; ii < (ts->rx_count * ts->tx_count - 1); ii++) {
snprintf(temp, CMD_RESULT_WORD_LEN, "%d ", ts->pFrame[ii]);
strncat(buffer, temp, CMD_RESULT_WORD_LEN);
memset(temp, 0x00, CMD_RESULT_WORD_LEN);
}
snprintf(temp, CMD_RESULT_WORD_LEN, "%d", ts->pFrame[ii]);
strncat(buffer, temp, CMD_RESULT_WORD_LEN);
ret = snprintf(buf, ts->rx_count * ts->tx_count * 6, buffer);
vfree(buffer);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return ret;
}
static ssize_t multi_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: %d\n", __func__,
ts->multi_count);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->multi_count);
}
static ssize_t multi_count_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->multi_count = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t wet_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: %d, %d\n", __func__,
ts->wet_count, ts->dive_count);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->wet_count);
}
static ssize_t wet_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->wet_count = 0;
ts->dive_count = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t comm_err_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: %d\n", __func__,
ts->multi_count);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->comm_err_count);
}
static ssize_t comm_err_count_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->comm_err_count = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t module_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[256] = { 0 };
input_info(true, &ts->client->dev, "%s: %d\n", __func__,
ts->multi_count);
snprintf(buff, sizeof(buff), "SE%02X%02X%02X%02X%02X%02X%02X",
ts->plat_data->panel_revision,
ts->plat_data->img_version_of_bin[2],
ts->plat_data->img_version_of_bin[3], ts->nv, ts->cal_count,
ts->pressure_cal_base, ts->pressure_cal_delta);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s", buff);
}
static ssize_t vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
unsigned char buffer[10] = { 0 };
snprintf(buffer, 5, ts->plat_data->firmware_name + 8);
return snprintf(buf, SEC_CMD_BUF_SIZE, "LSI_%s", buffer);
}
static ssize_t checksum_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->checksum_result = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t checksum_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: %d\n", __func__,
ts->checksum_result);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", ts->checksum_result);
}
static ssize_t holding_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->time_longest = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t holding_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: %ld\n", __func__,
ts->time_longest);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%ld", ts->time_longest);
}
static ssize_t all_touch_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev,
"%s: touch:%d, force:%d, aod:%d, spay:%d\n", __func__,
ts->all_finger_count, ts->all_force_count,
ts->all_aod_tap_count, ts->all_spay_count);
return snprintf(buf, SEC_CMD_BUF_SIZE,
"\"TTCN\":\"%d\",\"TFCN\":\"%d\",\"TACN\":\"%d\",\"TSCN\":\"%d\"",
ts->all_finger_count, ts->all_force_count,
ts->all_aod_tap_count, ts->all_spay_count);
}
static ssize_t all_touch_count_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->all_force_count = 0;
ts->all_aod_tap_count = 0;
ts->all_spay_count = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t z_value_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
input_info(true, &ts->client->dev, "%s: max:%d, min:%d, avg:%d\n",
__func__, ts->max_z_value, ts->min_z_value, ts->sum_z_value);
if (ts->all_finger_count)
return snprintf(buf, SEC_CMD_BUF_SIZE,
"\"TMXZ\":\"%d\",\"TMNZ\":\"%d\",\"TAVZ\":\"%d\"",
ts->max_z_value, ts->min_z_value,
ts->sum_z_value / ts->all_finger_count);
else
return snprintf(buf, SEC_CMD_BUF_SIZE,
"\"TMXZ\":\"%d\",\"TMNZ\":\"%d\"",
ts->max_z_value, ts->min_z_value);
}
static ssize_t z_value_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
ts->max_z_value = 0;
ts->min_z_value = 0xFFFFFFFF;
ts->sum_z_value = 0;
ts->all_finger_count = 0;
input_info(true, &ts->client->dev, "%s: clear\n", __func__);
return count;
}
static ssize_t pressure_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[256] = { 0 };
if (ts->lowpower_mode & SEC_TS_MODE_CUSTOMLIB_FORCE_KEY)
snprintf(buff, sizeof(buff), "1");
else
snprintf(buff, sizeof(buff), "0");
return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff);
}
static ssize_t pressure_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
int ret;
unsigned long value = 0;
if (count > 2)
return -EINVAL;
ret = kstrtoul(buf, 10, &value);
if (ret != 0)
return ret;
if (!ts->use_customlib)
return -EINVAL;
if (value == 1)
ts->lowpower_mode |= SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
else
ts->lowpower_mode &= ~SEC_TS_MODE_CUSTOMLIB_FORCE_KEY;
#ifdef SEC_TS_SUPPORT_CUSTOMLIB
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_ts_set_custom_library(ts);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
#endif
return count;
}
static ssize_t get_lp_dump_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
u8 string_data[8] = {0, };
u16 current_index;
int i, ret;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev, "%s: Touch is stopped!\n",
__func__);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return snprintf(buf, SEC_CMD_BUF_SIZE, "TSP turned off");
}
string_data[0] = SEC_TS_CMD_CUSTOMLIB_LP_DUMP & 0xFF;
string_data[1] = (SEC_TS_CMD_CUSTOMLIB_LP_DUMP & 0xFF00) >> 8;
disable_irq(ts->client->irq);
ret = ts->sec_ts_read_customlib(ts, string_data, 2);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: Failed to read rect\n",
__func__);
snprintf(buf, SEC_CMD_BUF_SIZE, "NG, Failed to read rect");
goto out;
}
current_index = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF);
if (current_index > 1000 || current_index < 500) {
input_err(true, &ts->client->dev,
"Failed to Custom Library LP log %d\n", current_index);
snprintf(buf, SEC_CMD_BUF_SIZE,
"NG, Failed to Custom Library LP log, current_index=%d",
current_index);
goto out;
}
input_info(true, &ts->client->dev,
"%s: DEBUG current_index = %d\n", __func__, current_index);
/* Custom Library has 62 stacks for LP dump */
for (i = 61; i >= 0; i--) {
u16 data0, data1, data2, data3;
char buff[30] = {0, };
u16 string_addr;
string_addr = current_index - (8 * i);
if (string_addr < 500)
string_addr += SEC_TS_CMD_CUSTOMLIB_LP_DUMP;
string_data[0] = string_addr & 0xFF;
string_data[1] = (string_addr & 0xFF00) >> 8;
ret = ts->sec_ts_read_customlib(ts, string_data, 8);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Failed to read rect\n", __func__);
snprintf(buf, SEC_CMD_BUF_SIZE,
"NG, Failed to read rect, addr=%d",
string_addr);
goto out;
}
data0 = (string_data[1] & 0xFF) << 8 | (string_data[0] & 0xFF);
data1 = (string_data[3] & 0xFF) << 8 | (string_data[2] & 0xFF);
data2 = (string_data[5] & 0xFF) << 8 | (string_data[4] & 0xFF);
data3 = (string_data[7] & 0xFF) << 8 | (string_data[6] & 0xFF);
if (data0 || data1 || data2 || data3) {
snprintf(buff, sizeof(buff),
"%d: %04x%04x%04x%04x\n",
string_addr, data0, data1, data2, data3);
strncat(buf, buff, SEC_CMD_BUF_SIZE);
}
}
out:
enable_irq(ts->client->irq);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return strlen(buf);
}
static ssize_t force_recal_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
u8 rbuf[4] = {0, };
u32 recal_count;
int ret;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: Touch is stopped!\n", __func__);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", -ENODEV);
}
ret = ts->sec_ts_read(ts, SEC_TS_READ_FORCE_RECAL_COUNT, rbuf, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Failed to read\n", __func__);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", -EIO);
}
recal_count = (rbuf[0] & 0xFF) << 24 | (rbuf[1] & 0xFF) << 16 |
(rbuf[2] & 0xFF) << 8 | (rbuf[3] & 0xFF);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return snprintf(buf, SEC_CMD_BUF_SIZE, "%d", recal_count);
}
/* sysfs file node to store heatmap mode
* "echo cmd > heatmap_mode" to change
* Possible commands:
* 0 = HEATMAP_OFF
* 1 = HEATMAP_PARTIAL
* 2 = HEATMAP_FULL
*/
static ssize_t heatmap_mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
struct sec_ts_plat_data *pdata = ts->plat_data;
int result;
int val;
u8 config;
result = kstrtoint(buf, 10, &val);
if (result < 0 || val < HEATMAP_OFF || val > HEATMAP_FULL) {
input_err(true, &ts->client->dev,
"%s: Invalid input.\n", __func__);
return -EINVAL;
}
pdata->heatmap_mode = val;
/* reset all heatmap settings when any change */
config = 0;
result = ts->sec_ts_write(ts,
SEC_TS_CMD_HEATMAP_ENABLE, &config, 1);
if (result < 0)
input_err(true, &ts->client->dev,
"%s: write reg %#x failed, returned %i\n",
__func__, SEC_TS_CMD_HEATMAP_ENABLE, result);
config = TYPE_INVALID_DATA;
result = ts->sec_ts_write(ts,
SEC_TS_CMD_MUTU_RAW_TYPE, &config, 1);
if (result < 0)
input_err(true, &ts->client->dev,
"%s: write reg %#x failed, returned %i\n",
__func__, SEC_TS_CMD_MUTU_RAW_TYPE, result);
return count;
#else
return 0;
#endif
}
static ssize_t heatmap_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#if IS_ENABLED(CONFIG_TOUCHSCREEN_HEATMAP)
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
const struct sec_ts_plat_data *pdata = ts->plat_data;
return scnprintf(buf, PAGE_SIZE, "%d\n",
pdata->heatmap_mode);
#else
return scnprintf(buf, PAGE_SIZE, "N/A\n");
#endif
}
static ssize_t fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
int ret, written = 0;
u8 data[3];
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
/* If there is no FW file avaiable,
* sec_ts_save_version_of_ic() and sec_ts_save_version_of_bin() will
* no be called. Need to get through SEC_TS_READ_IMG_VERSION cmd.
*/
if (ts->plat_data->panel_revision == 0 &&
ts->plat_data->img_version_of_bin[2] == 0 &&
ts->plat_data->img_version_of_bin[3] == 0) {
u8 fw_ver[4];
ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, fw_ver, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: firmware version read error\n", __func__);
goto out;
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"SE-V%02X.%02X.%02X\n",
ts->plat_data->panel_revision,
fw_ver[2],
fw_ver[3]);
written += scnprintf(buf + written, PAGE_SIZE - written,
"FW file: N/A\n");
} else {
written += scnprintf(buf + written, PAGE_SIZE - written,
"SE-V%02X.%02X.%02X\n",
ts->plat_data->panel_revision,
ts->plat_data->img_version_of_ic[2],
ts->plat_data->img_version_of_ic[3]);
written += scnprintf(buf + written, PAGE_SIZE - written,
"FW file: %s\n",
ts->plat_data->firmware_name);
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"Cal: %02X %02X %02X %02X %02X %02X %02X %02X\n",
ts->cali_report[0], ts->cali_report[1], ts->cali_report[2],
ts->cali_report[3], ts->cali_report[4], ts->cali_report[5],
ts->cali_report[6], ts->cali_report[7]);
ret = ts->sec_ts_read(ts, SEC_TS_READ_ID, data, sizeof(data));
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read device id(%d)\n",
__func__, ret);
goto out;
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"ID: %02X %02X %02X\n",
data[0], data[1], data[2]);
out:
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return written;
}
static ssize_t status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sec_cmd_data *sec = dev_get_drvdata(dev);
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
int written = 0;
unsigned char data[4] = { 0 };
int ret;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
data[0] = 0;
ret = ts->sec_ts_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read boot status(%d)\n",
__func__, ret);
goto out;
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"BOOT STATUS: 0x%02X\n", data[0]);
memset(data, 0x0, 4);
ret = ts->sec_ts_read(ts, SEC_TS_READ_TS_STATUS, data, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to touch status(%d)\n",
__func__, ret);
goto out;
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"TOUCH STATUS: 0x%02X, 0x%02X, 0x%02X, 0x%02X\n",
data[0], data[1], data[2], data[3]);
memset(data, 0x0, 2);
ret = ts->sec_ts_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, data, 2);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to read touch functions(%d)\n",
__func__, ret);
goto out;
}
written += scnprintf(buf + written, PAGE_SIZE - written,
"Functions: 0x%02X, 0x%02X\n", data[0], data[1]);
out:
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return written;
}
static DEVICE_ATTR_RO(ito_check);
static DEVICE_ATTR_RO(raw_check);
static DEVICE_ATTR_RW(multi_count);
static DEVICE_ATTR_RW(wet_mode);
static DEVICE_ATTR_RW(comm_err_count);
static DEVICE_ATTR_RW(checksum);
static DEVICE_ATTR_RW(holding_time);
static DEVICE_ATTR_RW(all_touch_count);
static DEVICE_ATTR_RW(z_value);
static DEVICE_ATTR_RO(module_id);
static DEVICE_ATTR_RO(vendor);
static DEVICE_ATTR_RW(pressure_enable);
static DEVICE_ATTR_RO(get_lp_dump);
static DEVICE_ATTR_RO(force_recal_count);
static DEVICE_ATTR_RW(heatmap_mode);
static DEVICE_ATTR_RO(fw_version);
static DEVICE_ATTR_RO(status);
static struct attribute *cmd_attributes[] = {
&dev_attr_scrub_pos.attr,
&dev_attr_ito_check.attr,
&dev_attr_raw_check.attr,
&dev_attr_multi_count.attr,
&dev_attr_wet_mode.attr,
&dev_attr_comm_err_count.attr,
&dev_attr_checksum.attr,
&dev_attr_holding_time.attr,
&dev_attr_all_touch_count.attr,
&dev_attr_z_value.attr,
&dev_attr_module_id.attr,
&dev_attr_vendor.attr,
&dev_attr_pressure_enable.attr,
&dev_attr_get_lp_dump.attr,
&dev_attr_force_recal_count.attr,
&dev_attr_heatmap_mode.attr,
&dev_attr_fw_version.attr,
&dev_attr_status.attr,
NULL,
};
static struct attribute_group cmd_attr_group = {
.attrs = cmd_attributes,
};
static int sec_ts_check_index(struct sec_ts_data *ts)
{
struct sec_cmd_data *sec = &ts->sec;
char buff[SEC_CMD_STR_LEN] = { 0 };
int node;
if (sec->cmd_param[0] < 0 || sec->cmd_param[0] > ts->tx_count
|| sec->cmd_param[1] < 0 || sec->cmd_param[1] > ts->rx_count) {
snprintf(buff, sizeof(buff), "%s", "NG");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_FAIL;
input_info(true, &ts->client->dev,
"%s: parameter error: %u, %u\n",
__func__, sec->cmd_param[0], sec->cmd_param[0]);
node = -1;
return node;
}
node = sec->cmd_param[1] * ts->tx_count + sec->cmd_param[0];
input_info(true, &ts->client->dev, "%s: node = %d\n", __func__, node);
return node;
}
static void fw_update(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[64] = { 0 };
int retval = 0;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: [ERROR] Touch is stopped\n", __func__);
snprintf(buff, sizeof(buff), "%s", "TSP turned off");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
}
retval = sec_ts_firmware_update_on_hidden_menu(ts, sec->cmd_param[0]);
if (retval < 0) {
snprintf(buff, sizeof(buff), "%s", "NA");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_FAIL;
input_err(true, &ts->client->dev, "%s: failed [%d]\n",
__func__, retval);
} else {
snprintf(buff, sizeof(buff), "%s", "OK");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: success [%d]\n",
__func__, retval);
}
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
int sec_ts_fix_tmode(struct sec_ts_data *ts, u8 mode, u8 state)
{
int ret;
u8 onoff[1] = {STATE_MANAGE_OFF};
u8 tBuff[2] = { mode, state };
input_info(true, &ts->client->dev, "%s: mode %d state %d\n",
__func__, mode, state);
ret = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON, onoff, 1);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: write reg %#x failed, return %i\n",
__func__, SEC_TS_CMD_STATEMANAGE_ON, ret);
sec_ts_delay(20);
ret = ts->sec_ts_write(ts, SEC_TS_CMD_CHG_SYSMODE, tBuff,
sizeof(tBuff));
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: write reg %#x failed, return %i\n",
__func__, SEC_TS_CMD_CHG_SYSMODE, ret);
sec_ts_delay(20);
return ret;
}
int sec_ts_release_tmode(struct sec_ts_data *ts)
{
int ret;
u8 onoff[1] = {STATE_MANAGE_ON};
input_info(true, &ts->client->dev, "%s\n", __func__);
ret = ts->sec_ts_write(ts, SEC_TS_CMD_STATEMANAGE_ON, onoff, 1);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: write reg %#x failed, return %i\n",
__func__, SEC_TS_CMD_STATEMANAGE_ON, ret);
sec_ts_delay(20);
return ret;
}
/* sec_ts_cm_spec_over_check : apply gap calculation with ts->pFrame data
* gap = abs(N1 - N2) / MAX(N1, N2) * 100 (%)
*/
static int sec_ts_cm_spec_over_check(struct sec_ts_data *ts, short *gap,
bool gap_dir)
{
int i = 0;
int j = 0;
int gapx, gapy, pos1, pos2;
short dpos1, dpos2;
int specover_count = 0;
input_info(true, &ts->client->dev, "%s\n", __func__);
/* Get x-direction cm gap */
if (!gap_dir) {
input_info(true, &ts->client->dev, "gapX TX\n");
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count - 1; j++) {
/* Exclude last line to get gap between two
* lines.
*/
pos1 = (i * ts->tx_count) + j;
pos2 = (i * ts->tx_count) + (j + 1);
dpos1 = ts->pFrame[pos1];
dpos2 = ts->pFrame[pos2];
if (dpos1 > dpos2)
gapx = 100 - (dpos2 * 100 / dpos1);
else
gapx = 100 - (dpos1 * 100 / dpos2);
gap[pos1] = gapx;
if (gapx > cm_gap[i][j])
specover_count++;
}
}
}
/* get y-direction cm gap */
else {
input_info(true, &ts->client->dev, "gapY RX\n");
for (i = 0; i < ts->rx_count - 1; i++) {
for (j = 0; j < ts->tx_count; j++) {
pos1 = (i * ts->tx_count) + j;
pos2 = ((i + 1) * ts->tx_count) + j;
dpos1 = ts->pFrame[pos1];
dpos2 = ts->pFrame[pos2];
if (dpos1 > dpos2)
gapy = 100 - (dpos2 * 100 / dpos1);
else
gapy = 100 - (dpos1 * 100 / dpos2);
gap[pos1] = gapy;
if (gapy > cm_gap[i][j])
specover_count++;
}
}
}
input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
gap_dir == 0 ? "gapX" : "gapY", specover_count);
return specover_count;
}
static int sec_ts_cs_spec_over_check(struct sec_ts_data *ts, short *gap)
{
int i;
int specover_count = 0;
short dTmp;
for (i = 0; i < ts->tx_count - 1; i++) {
dTmp = ts->pFrame[i] - ts->pFrame[i + 1];
if (dTmp < 0)
dTmp *= -1;
gap[i] = dTmp;
if (dTmp > cs_tx_gap)
specover_count++;
}
for (i = ts->tx_count; i < ts->tx_count + ts->rx_count - 1; i++) {
dTmp = ts->pFrame[i] - ts->pFrame[i + 1];
if (dTmp < 0)
dTmp *= -1;
gap[i] = dTmp;
if (dTmp > cs_rx_gap)
specover_count++;
}
input_info(true, &ts->client->dev, "%s: Gap NG for %d node(s)\n",
__func__, specover_count);
return specover_count;
}
static int sec_ts_get_gain_table(struct sec_ts_data *ts)
{
int i, j;
int temp;
int tmp_dv;
unsigned int str_size, str_len = 0;
unsigned char *pStr = NULL;
input_info(true, &ts->client->dev, "%s\n", __func__);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
tmp_dv = ts->pFrame[i * ts->tx_count + j];
/* skip notch area */
if (cm_region[i][j] == REGION_NOTCH) {
ts->gainTable[j * ts->rx_count + i] = 0;
continue;
}
if (tmp_dv <= 0) {
input_info(true, &ts->client->dev,
"%s: node[%d,%d] == 0\n", __func__, i,
j);
tmp_dv = 1;
}
temp = (fs_target[i][j] * 1000) / (tmp_dv) * 64;
/* Add 500 to round the result */
temp = (temp + 500) / 1000;
if (temp > 255)
temp = 255;
ts->gainTable[j * ts->rx_count + i] = (temp & 0xFF);
}
}
str_size = 6 * (ts->tx_count + 1);
pStr = kzalloc(str_size, GFP_KERNEL);
if (pStr == NULL)
return -ENOMEM;
input_info(true, &ts->client->dev, "%s: Gain Table\n", __func__);
for (i = 0; i < ts->rx_count; i++) {
pStr[0] = 0;
str_len = 0;
for (j = 0; j < ts->tx_count; j++) {
str_len += scnprintf(pStr + str_len, str_size - str_len,
" %3d",
ts->gainTable[(j * ts->rx_count) + i]);
}
input_info(true, &ts->client->dev, "%s\n", pStr);
}
kfree(pStr);
return 0;
}
static int sec_ts_write_gain_table(struct sec_ts_data *ts)
{
int node_cnt = ts->tx_count * ts->rx_count;
u8 *gainTable = NULL;
u8 *tCmd = NULL;
int copy_max, copy_left, copy_size, copy_cur;
int ret = -1;
input_info(true, &ts->client->dev, "%s\n", __func__);
/* Write norm table to ic
* divide data into 256 bytes:
* buffer size limit 256 bytes
*/
gainTable = ts->gainTable;
copy_max = ts->io_burstmax - 3;
copy_left = node_cnt;
copy_size = 0;
copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
tCmd = kzalloc(copy_cur + 3, GFP_KERNEL);
if (!tCmd)
goto ErrorAlloc;
while (copy_left > 0) {
tCmd[0] = SEC_TS_CMD_WRITE_NORM_TABLE;
tCmd[1] = (copy_size >> 8) & 0xFF;
tCmd[2] = (copy_size >> 0) & 0xFF;
memcpy(&tCmd[3], &gainTable[copy_size], copy_cur);
input_info(true, &ts->client->dev,
"%s: left = %d, cur = %d, size = %d\n",
__func__, copy_left, copy_cur, copy_size);
ret = ts->sec_ts_write_burst_heap(ts, tCmd, 3 + copy_cur);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: table write failed\n", __func__);
copy_size += copy_cur;
copy_left -= copy_cur;
copy_cur = (copy_left > copy_max) ? copy_max : copy_left;
}
ErrorAlloc:
kfree(tCmd);
return ret;
}
/* sec_ts_get_postcal_mean : get mean value for all nodes */
static int sec_ts_get_postcal_mean(struct sec_ts_data *ts)
{
int i, j;
int sum = 0;
int nCnt = 0;
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if (cm_region[i][j] == REGION_NOTCH) {
/* Count notch nodes, where fs target is 0 */
nCnt++;
continue;
}
sum += ts->pFrame[(i * ts->tx_count) + j];
}
}
/* exclude notch area from average */
sum = sum / (ts->tx_count * ts->rx_count - nCnt);
return sum;
}
static int sec_ts_get_postcal_uniformity(struct sec_ts_data *ts, short *diff)
{
int pos1, pos2;
short dpos1, dpos2, gap;
int i = 0;
int j = 0;
int specover_cnt = 0;
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count - 1; j++) {
/* At the notch boundary, skip (leave gap as 0)
* if node[row][col] or node[row][col+1] is 0,
* it is notch boundary for column direction
*/
if ((cm_region[i][j] == REGION_NOTCH) ||
(cm_region[i][j + 1] == REGION_NOTCH))
continue;
pos1 = (i * ts->tx_count) + j;
pos2 = (i * ts->tx_count) + (j + 1);
dpos1 = ts->pFrame[pos1];
dpos2 = ts->pFrame[pos2];
gap = (dpos1 > dpos2) ? (dpos1 - dpos2) :
(dpos2 - dpos1);
diff[pos1] = gap;
}
}
for (i = 0; i < ts->rx_count - 1; i++) {
for (j = 0; j < ts->tx_count; j++) {
/* At the notch boundary, skip (leave gap as 0)
* if node[row][col] or node[row+1][col] is 0,
* it is notch boundary for row direction
*/
if ((cm_region[i][j] == REGION_NOTCH) ||
(cm_region[i + 1][j] == REGION_NOTCH))
continue;
pos1 = (i * ts->tx_count) + j;
pos2 = ((i + 1) * ts->tx_count) + j;
dpos1 = ts->pFrame[pos1];
dpos2 = ts->pFrame[pos2];
gap = (dpos1 > dpos2) ? (dpos1 - dpos2) :
(dpos2 - dpos1);
/* find max gap between x and y direction */
if (diff[pos1] < gap)
diff[pos1] = gap;
}
}
for (i = 0; i < ts->rx_count * ts->tx_count; i++) {
/* since spec is in % unit, multiply 100 */
diff[i] *= 100;
diff[i] /= (ts->fs_postcal_mean);
if (diff[i] > fs_postcal_uniform_spec)
specover_cnt++;
}
return specover_cnt;
}
static void sec_ts_print_frame(struct sec_ts_data *ts, short *min, short *max)
{
int i = 0;
int j = 0;
const unsigned int buff_size = 6 * (ts->tx_count + 1);
unsigned int buff_len = 0;
unsigned char *pStr = NULL;
input_info(true, &ts->client->dev, "%s\n", __func__);
pStr = kzalloc(buff_size, GFP_KERNEL);
if (pStr == NULL)
return;
buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
" TX");
for (i = 0; i < ts->tx_count; i++)
buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
" %02d ", i);
input_info(true, &ts->client->dev, "%s\n", pStr);
buff_len = 0;
memset(pStr, 0x0, buff_size);
buff_len += scnprintf(pStr + buff_len, buff_size - buff_len, " +");
for (i = 0; i < ts->tx_count; i++)
buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
"----");
input_info(true, &ts->client->dev, "%s\n", pStr);
for (i = 0; i < ts->rx_count; i++) {
buff_len = 0;
memset(pStr, 0x0, buff_size);
buff_len += scnprintf(pStr + buff_len, buff_size - buff_len,
"Rx%02d | ", i);
for (j = 0; j < ts->tx_count; j++) {
buff_len += scnprintf(pStr + buff_len,
buff_size - buff_len,
" %3d", ts->pFrame[(j * ts->rx_count) + i]);
if (i > 0) {
if (ts->pFrame[(j * ts->rx_count) + i] < *min)
*min = ts->pFrame[(j * ts->rx_count) +
i];
if (ts->pFrame[(j * ts->rx_count) + i] > *max)
*max = ts->pFrame[(j * ts->rx_count) +
i];
}
}
input_info(true, &ts->client->dev, "%s\n", pStr);
}
kfree(pStr);
}
static int sec_ts_read_frame(struct sec_ts_data *ts, u8 type, short *min,
short *max, enum spec_check_type *spec_check)
{
unsigned int readbytes = 0xFF;
unsigned char *pRead = NULL;
u8 mode = TYPE_INVALID_DATA;
int ret = 0;
int i = 0;
int j = 0;
short dTmp = 0;
short *temp = NULL;
u8 w_type;
input_info(true, &ts->client->dev, "%s\n", __func__);
/* set data length, allocation buffer memory */
readbytes = ts->rx_count * ts->tx_count * 2;
pRead = kzalloc(readbytes, GFP_KERNEL);
if (!pRead)
return -ENOMEM;
/* set OPCODE and data type */
if (type == TYPE_OFFSET_DATA_SDC_CM2)
w_type = TYPE_OFFSET_DATA_SDC;
else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
w_type = TYPE_OFFSET_DATA_SDC;
else
w_type = type;
/* Set raw type to TYPE_INVALID_DATA if change before */
ret = ts->sec_ts_read(ts,
SEC_TS_CMD_MUTU_RAW_TYPE, &ts->ms_frame_type, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: read rawdata type failed\n",
__func__);
goto ErrorExit;
}
if (ts->ms_frame_type != TYPE_INVALID_DATA) {
ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &mode, 1);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: recover rawdata type failed\n", __func__);
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &w_type, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Set rawdata type failed\n", __func__);
goto ErrorExit;
}
ts->ms_frame_type = w_type;
sec_ts_delay(50);
if (type == TYPE_OFFSET_DATA_SDC || type == TYPE_OFFSET_DATA_SDC_CM2
|| type == TYPE_OFFSET_DATA_SDC_NOT_SAVE) {
/* excute selftest for real cap offset data, because real cap
* data is not memory data in normal touch.
**/
char para = TO_TOUCH_MODE;
disable_irq(ts->client->irq);
if (type == TYPE_OFFSET_DATA_SDC)
execute_selftest(ts,
TEST_OPEN | TEST_NODE_VARIANCE);
else if (type ==
TYPE_OFFSET_DATA_SDC_CM2)
execute_selftest(ts,
TEST_OPEN | TEST_NOT_SAVE | TEST_HIGH_FREQ);
else if (type ==
TYPE_OFFSET_DATA_SDC_NOT_SAVE)
execute_selftest(ts,
TEST_OPEN | TEST_NODE_VARIANCE | TEST_NOT_SAVE);
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Set powermode failed\n", __func__);
enable_irq(ts->client->irq);
goto ErrorRelease;
}
/* read data and check ret later */
ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA, pRead,
readbytes);
enable_irq(ts->client->irq);
} else
/* read data and check ret later */
ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_RAWDATA, pRead,
readbytes);
/* check read data */
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: read rawdata failed!\n", __func__);
goto ErrorRelease;
}
memset(ts->pFrame, 0x00, readbytes);
for (i = 0; i < readbytes; i += 2)
ts->pFrame[i / 2] = pRead[i + 1] + (pRead[i] << 8);
#ifdef DEBUG_MSG
input_info(true, &ts->client->dev,
"%s: 02X%02X%02X readbytes=%d\n", __func__,
pRead[0], pRead[1], pRead[2], readbytes);
#endif
sec_ts_print_frame(ts, min, max);
temp = kzalloc(readbytes, GFP_KERNEL);
if (!temp)
goto ErrorRelease;
memcpy(temp, ts->pFrame, ts->tx_count * ts->rx_count * 2);
memset(ts->pFrame, 0x00, ts->tx_count * ts->rx_count * 2);
for (i = 0; i < ts->tx_count; i++) {
for (j = 0; j < ts->rx_count; j++)
ts->pFrame[(j * ts->tx_count) + i] =
temp[(i * ts->rx_count) + j];
}
/* spec check */
if (*spec_check == SPEC_CHECK) {
int specover_count = 0;
if (type == TYPE_OFFSET_DATA_SDC) {
unsigned int region = 0;
/* set initial value for min, max */
for (i = 0; i < REGION_TYPE_COUNT; i++) {
min[i] = SHRT_MAX;
max[i] = SHRT_MIN;
}
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
dTmp = ts->pFrame[i * ts->tx_count + j];
region = cm_region[i][j];
if (region == REGION_NOTCH)
continue;
min[region] = min(min[region], dTmp);
max[region] = max(max[region], dTmp);
if (dTmp > cm_max[region])
specover_count++;
if (dTmp < cm_min[region])
specover_count++;
}
}
input_info(true, &ts->client->dev,
"%s: type = %d, specover = %d\n",
__func__, type, specover_count);
if (specover_count == 0 &&
(max[REGION_NORMAL] - min[REGION_NORMAL] <
cm_mm[REGION_NORMAL]) &&
(max[REGION_EDGE] - min[REGION_EDGE] <
cm_mm[REGION_EDGE]) &&
(max[REGION_CORNER] - min[REGION_CORNER] <
cm_mm[REGION_CORNER]))
*spec_check = SPEC_PASS;
else
*spec_check = SPEC_FAIL;
} else if (type == TYPE_NOI_P2P_MIN) {
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
dTmp = ts->pFrame[i * ts->tx_count + j];
if (cm_region[i][j] != REGION_NOTCH &&
dTmp < noi_min[i][j])
specover_count++;
}
}
input_info(true, &ts->client->dev,
"%s: type = %d, specover = %d\n",
__func__, type, specover_count);
if (specover_count == 0)
*spec_check = SPEC_PASS;
else
*spec_check = SPEC_FAIL;
} else if (type == TYPE_NOI_P2P_MAX) {
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
dTmp = ts->pFrame[i * ts->tx_count + j];
if (cm_region[i][j] != REGION_NOTCH &&
dTmp > noi_max[i][j])
specover_count++;
}
}
input_info(true, &ts->client->dev,
"%s: type = %d, specover = %d\n",
__func__, type, specover_count);
if (specover_count == 0)
*spec_check = SPEC_PASS;
else
*spec_check = SPEC_FAIL;
}
}
kfree(temp);
ErrorRelease:
/* release data monitory (unprepare AFE data memory) */
ret = ts->sec_ts_write(ts, SEC_TS_CMD_MUTU_RAW_TYPE, &mode, 1);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: Set rawdata type failed\n", __func__);
else
ts->ms_frame_type = mode;
ErrorExit:
kfree(pRead);
return ret;
}
static void sec_ts_print_channel(struct sec_ts_data *ts)
{
unsigned char *pStr = NULL;
unsigned int str_size, str_len = 0;
int i = 0, j = 0, k = 0;
if (!ts->tx_count)
return;
str_size = 7 * (ts->tx_count + 1);
pStr = vzalloc(str_size);
if (!pStr)
return;
str_len = scnprintf(pStr, str_size, " TX");
for (k = 0; k < ts->tx_count; k++) {
str_len += scnprintf(pStr + str_len, str_size - str_len,
" %02d", k);
}
input_info(true, &ts->client->dev, "%s\n", pStr);
str_len = scnprintf(pStr, str_size, " +");
for (k = 0; k < ts->tx_count; k++) {
str_len += scnprintf(pStr + str_len, str_size - str_len,
"------");
}
input_info(true, &ts->client->dev, "%s\n", pStr);
str_len = scnprintf(pStr, str_size, " | ");
for (i = 0; i < (ts->tx_count + ts->rx_count) * 2; i += 2) {
if (j == ts->tx_count) {
input_info(true, &ts->client->dev, "%s\n", pStr);
input_info(true, &ts->client->dev, "\n");
str_len = scnprintf(pStr, str_size, " RX");
for (k = 0; k < ts->tx_count; k++) {
str_len += scnprintf(pStr + str_len,
str_size - str_len,
" %02d", k);
}
input_info(true, &ts->client->dev, "%s\n", pStr);
str_len = scnprintf(pStr, str_size, " +");
for (k = 0; k < ts->tx_count; k++) {
str_len += scnprintf(pStr + str_len,
str_size - str_len,
"------");
}
input_info(true, &ts->client->dev, "%s\n", pStr);
str_len = scnprintf(pStr, str_size, " | ");
} else if (j && !(j % ts->tx_count)) {
input_info(true, &ts->client->dev, "%s\n", pStr);
str_len = scnprintf(pStr, str_size, " | ");
}
str_len += scnprintf(pStr + str_len, str_size - str_len, " %5d",
ts->pFrame[j]);
j++;
}
input_info(true, &ts->client->dev, "%s\n", pStr);
vfree(pStr);
}
static int sec_ts_read_channel(struct sec_ts_data *ts, u8 type, short *min,
short *max, enum spec_check_type *spec_check)
{
unsigned char *pRead = NULL;
u8 mode = TYPE_INVALID_DATA;
int ret = 0;
int ii = 0;
int jj = 0;
unsigned int data_length = (ts->tx_count + ts->rx_count) * 2;
u8 w_data;
input_info(true, &ts->client->dev, "%s\n", __func__);
pRead = kzalloc(data_length, GFP_KERNEL);
if (!pRead)
return -ENOMEM;
/* set OPCODE and data type */
if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
w_data = TYPE_OFFSET_DATA_SDC;
else
w_data = type;
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &w_data, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: Set rawdata type failed\n", __func__);
goto out_read_channel;
}
sec_ts_delay(50);
if (type == TYPE_OFFSET_DATA_SDC ||
type == TYPE_OFFSET_DATA_SDC_NOT_SAVE) {
/* excute selftest for real cap offset data, because real cap
* data is not memory data in normal touch.
**/
char para = TO_TOUCH_MODE;
disable_irq(ts->client->irq);
if (type == TYPE_OFFSET_DATA_SDC)
execute_selftest(ts, TEST_SELF_NODE);
else if (type == TYPE_OFFSET_DATA_SDC_NOT_SAVE)
execute_selftest(ts, TEST_SELF_NODE | TEST_NOT_SAVE);
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SET_POWER_MODE, &para, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: set rawdata type failed!\n", __func__);
enable_irq(ts->client->irq);
goto err_read_data;
}
/* read data and check ret later */
ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
pRead, data_length);
enable_irq(ts->client->irq);
/* end */
} else
/* read data and check ret later */
ret = ts->sec_ts_read_heap(ts, SEC_TS_READ_TOUCH_SELF_RAWDATA,
pRead, data_length);
/* check read data */
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: read rawdata failed!\n", __func__);
goto err_read_data;
}
/* clear all pFrame data */
memset(ts->pFrame, 0x00, data_length);
/* d[00] ~ d[14] : TX channel
* d[15] ~ d[51] : none
* d[52] ~ d[77] : RX channel
* d[78] ~ d[103] : none
*/
for (ii = 0; ii < data_length; ii += 2) {
ts->pFrame[jj] = ((pRead[ii] << 8) | pRead[ii + 1]);
jj++;
}
sec_ts_print_channel(ts);
if (*spec_check == SPEC_CHECK) {
int specover_count = 0;
if (type == TYPE_OFFSET_DATA_SDC) {
min[0] = min[1] = SHRT_MAX;
max[0] = max[1] = SHRT_MIN;
for (ii = 0; ii < ts->tx_count; ii++) {
if (ts->pFrame[ii] > cs_tx_max)
specover_count++;
if (ts->pFrame[ii] < cs_tx_min)
specover_count++;
min[0] = min(min[0], ts->pFrame[ii]);
max[0] = max(max[0], ts->pFrame[ii]);
}
for (ii = ts->tx_count;
ii < ts->tx_count + ts->rx_count; ii++) {
if (ts->pFrame[ii] > cs_rx_max)
specover_count++;
if (ts->pFrame[ii] < cs_rx_min)
specover_count++;
min[1] = min(min[1], ts->pFrame[ii]);
max[1] = max(max[1], ts->pFrame[ii]);
}
}
input_info(true, &ts->client->dev,
"%s: type : %d, specover = %d\n",
__func__, type, specover_count);
if (specover_count == 0 &&
(max[0] - min[0]) < cs_tx_mm &&
(max[1] - min[1]) < cs_rx_mm)
*spec_check = SPEC_PASS;
else
*spec_check = SPEC_FAIL;
}
err_read_data:
/* release data monitory (unprepare AFE data memory) */
ret = ts->sec_ts_write(ts, SEC_TS_CMD_SELF_RAW_TYPE, &mode, 1);
if (ret < 0)
input_err(true, &ts->client->dev,
"%s: Set rawdata type failed\n", __func__);
out_read_channel:
kfree(pRead);
return ret;
}
static int sec_ts_read_gain_table(struct sec_ts_data *ts)
{
int readbytes = ts->tx_count * ts->rx_count;
unsigned char *pRead = NULL;
short min = 0;
short max = 0;
int ret;
int i;
/* readbytes : 1 byte for enable/disable info + 1 byte per node */
pRead = kzalloc(1 + readbytes, GFP_KERNEL);
if (!pRead)
return -ENOMEM;
ret = ts->sec_ts_read_heap(ts, SEC_TS_CMD_READ_NORM_TABLE, pRead,
1 + readbytes);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: read rawdata failed!\n",
__func__);
goto ErrorRead;
}
input_info(true, &ts->client->dev, "%s: gain table is %s\n",
__func__, pRead[0] ? "On." : "Off.");
for (i = 0; i < readbytes; i++)
ts->pFrame[i] = (short)pRead[i + 1];
sec_ts_print_frame(ts, &min, &max);
ErrorRead:
kfree(pRead);
return ret;
}
int sec_ts_read_raw_data(struct sec_ts_data *ts,
struct sec_cmd_data *sec, struct sec_ts_test_mode *mode)
{
int ii, jj;
int ret = 0;
const unsigned int buff_size = ts->tx_count * ts->rx_count *
CMD_RESULT_WORD_LEN;
unsigned int buff_len = 0;
char *buff;
buff = kzalloc(buff_size, GFP_KERNEL);
if (!buff)
goto error_alloc_mem;
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: [ERROR] Touch is stopped\n", __func__);
goto error_power_state;
}
input_info(true, &ts->client->dev, "%s: %d, %s\n",
__func__, mode->type, mode->allnode ? "ALL" : "");
ret = sec_ts_fix_tmode(ts, TOUCH_SYSTEM_MODE_TOUCH,
TOUCH_MODE_STATE_TOUCH);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: failed to fix tmode\n",
__func__);
goto error_test_fail;
}
if (mode->frame_channel)
ret = sec_ts_read_channel(ts, mode->type, mode->min,
mode->max, &mode->spec_check);
else
ret = sec_ts_read_frame(ts, mode->type, mode->min,
mode->max, &mode->spec_check);
if (ret < 0) {
input_err(true, &ts->client->dev, "%s: failed to read frame\n",
__func__);
goto error_test_fail;
}
if (mode->allnode) {
if (mode->frame_channel) {
if (mode->spec_check == SPEC_PASS) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"OK %d %d",
ts->rx_count, ts->tx_count);
} else if (mode->spec_check == SPEC_FAIL) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"NG %d %d",
ts->rx_count, ts->tx_count);
}
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len, "\n ");
if (!ts->print_format) {
for (ii = 0;
ii < (ts->rx_count + ts->tx_count);
ii++) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"%3d,", ts->pFrame[ii]);
if (ii >= ts->tx_count - 1)
buff_len += scnprintf(
buff + buff_len,
buff_size - buff_len,
"\n");
}
} else {
for (ii = ts->tx_count;
ii < (ts->rx_count + ts->tx_count);
ii++) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"%3d,", ts->pFrame[ii]);
}
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len, "\n");
for (ii = 0; ii < ts->tx_count; ii++) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"%3d,\n", ts->pFrame[ii]);
}
}
} else {
if (mode->spec_check == SPEC_NO_CHECK)
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len, "\n");
else if (mode->spec_check == SPEC_PASS) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"OK %d %d\n",
ts->rx_count, ts->tx_count);
} else { /* mode->spec_check == SPEC_FAIL) */
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"NG %d %d\n", ts->rx_count,
ts->tx_count);
}
if (!ts->print_format) {
for (ii = 0;
ii < (ts->rx_count * ts->tx_count); ii++) {
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"%3d,", ts->pFrame[ii]);
if (ii % ts->tx_count == (ts->tx_count - 1))
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"\n");
}
} else {
for (ii = 0; ii < ts->tx_count; ii++) {
for (jj = 0; jj < ts->rx_count; jj++) {
buff_len += scnprintf(
buff + buff_len,
buff_size - buff_len,
"%3d,",
ts->pFrame[(jj *
ts->tx_count) + ii]);
}
buff_len += scnprintf(buff + buff_len,
buff_size - buff_len,
"\n");
}
}
}
} else {
buff_len += scnprintf(buff + buff_len, buff_size - buff_len,
"%3d,%3d", mode->min[0], mode->max[0]);
}
ret = sec_ts_release_tmode(ts);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: failed to release tmode\n", __func__);
goto error_test_fail;
}
if (!sec)
goto out_rawdata;
sec_cmd_set_cmd_result(sec, buff, buff_len);
sec->cmd_state = SEC_CMD_STATUS_OK;
out_rawdata:
kfree(buff);
sec_ts_locked_release_all_finger(ts);
return ret;
error_test_fail:
error_power_state:
kfree(buff);
error_alloc_mem:
if (!sec)
return ret;
sec_cmd_set_cmd_result(sec, "FAIL", 4);
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_ts_locked_release_all_finger(ts);
return ret;
}
int sec_ts_check_fs_precal(struct sec_ts_data *ts)
{
int i, j;
int fail_count = 0;
short temp;
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
temp = ts->pFrame[i * ts->tx_count + j];
if (cm_region[i][j] == REGION_NOTCH)
continue;
/* check whether fs_precal data is within range */
if ((temp > fs_precal_h[i][j]) ||
(temp < fs_precal_l[i][j]))
fail_count++;
}
}
return fail_count;
}
static void get_fw_ver_bin(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[16] = { 0 };
sec_cmd_set_default_result(sec);
snprintf(buff, sizeof(buff), "SE-V%02X.%02X.%02X",
ts->plat_data->panel_revision,
ts->plat_data->img_version_of_bin[2],
ts->plat_data->img_version_of_bin[3]);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
static void get_fw_ver_ic(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[16] = { 0 };
int ret;
u8 fw_ver[4];
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: [ERROR] Touch is stopped\n", __func__);
snprintf(buff, sizeof(buff), "%s", "TSP turned off");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
}
ret = ts->sec_ts_read(ts, SEC_TS_READ_IMG_VERSION, fw_ver, 4);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: firmware version read error\n", __func__);
snprintf(buff, sizeof(buff), "%s", "NG");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
}
snprintf(buff, sizeof(buff), "SE-V%02X.%02X.%02X",
ts->plat_data->panel_revision, fw_ver[2], fw_ver[3]);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void get_config_ver(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[22] = { 0 };
sec_cmd_set_default_result(sec);
snprintf(buff, sizeof(buff), "%s_SE_%02X%02X",
ts->plat_data->model_name,
ts->plat_data->config_version_of_ic[2],
ts->plat_data->config_version_of_ic[3]);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
#ifdef PAT_CONTROL
static void get_pat_information(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[22] = { 0 };
sec_cmd_set_default_result(sec);
/* fixed tune version will be saved at excute autotune */
snprintf(buff, sizeof(buff), "P%02XT%04X",
ts->cal_count, ts->tune_fix_ver);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
static void set_external_factory(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[22] = { 0 };
sec_cmd_set_default_result(sec);
ts->external_factory = true;
snprintf(buff, sizeof(buff), "OK");
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
#endif
static void get_threshold(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[20] = { 0 };
char threshold[2] = { 0 };
int ret;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: [ERROR] Touch is stopped\n", __func__);
snprintf(buff, sizeof(buff), "%s", "TSP turned off");
goto err;
}
ret = ts->sec_ts_write(ts, SEC_TS_CMD_TOUCH_MODE_FOR_THRESHOLD,
threshold, 1);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: threshold write type failed. ret: %d\n",
__func__, ret);
snprintf(buff, sizeof(buff), "%s", "NG");
goto err;
}
ret = ts->sec_ts_read(ts, SEC_TS_CMD_TOUCH_THRESHOLD, threshold, 2);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: read threshold fail!\n", __func__);
snprintf(buff, sizeof(buff), "%s", "NG");
goto err;
}
input_info(true, &ts->client->dev, "0x%02X, 0x%02X\n",
threshold[0], threshold[1]);
snprintf(buff, sizeof(buff), "%d", (threshold[0] << 8) | threshold[1]);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
err:
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_NOT_APPLICABLE;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void module_off_master(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[3] = { 0 };
int ret = 0;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
ret = sec_ts_stop_device(ts);
if (ret == 0)
snprintf(buff, sizeof(buff), "%s", "OK");
else
snprintf(buff, sizeof(buff), "%s", "NG");
sec_cmd_set_default_result(sec);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
if (strncmp(buff, "OK", 2) == 0)
sec->cmd_state = SEC_CMD_STATUS_OK;
else
sec->cmd_state = SEC_CMD_STATUS_FAIL;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void module_on_master(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[3] = { 0 };
int ret = 0;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
ret = sec_ts_start_device(ts);
/* TODO: check this for SPI case
* if (ts->input_dev->disabled) {
* sec_ts_set_lowpowermode(ts, TO_LOWPOWER_MODE);
* ts->power_status = SEC_TS_STATE_LPM;
* }
**/
if (ret == 0)
snprintf(buff, sizeof(buff), "%s", "OK");
else
snprintf(buff, sizeof(buff), "%s", "NG");
sec_cmd_set_default_result(sec);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
if (strncmp(buff, "OK", 2) == 0)
sec->cmd_state = SEC_CMD_STATUS_OK;
else
sec->cmd_state = SEC_CMD_STATUS_FAIL;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
}
static void get_chip_vendor(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[16] = { 0 };
strncpy(buff, "SEC", sizeof(buff));
sec_cmd_set_default_result(sec);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
static void get_chip_name(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[16] = { 0 };
if (ts->plat_data->img_version_of_ic[0] == 0x02)
strncpy(buff, "MC44", sizeof(buff));
else if (ts->plat_data->img_version_of_ic[0] == 0x05)
strncpy(buff, "A552", sizeof(buff));
else if (ts->plat_data->img_version_of_ic[0] == 0x09)
strncpy(buff, "Y661", sizeof(buff));
else if (ts->plat_data->img_version_of_ic[0] == 0x10)
strncpy(buff, "Y761", sizeof(buff));
else
strncpy(buff, "N/A", sizeof(buff));
sec_cmd_set_default_result(sec);
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec->cmd_state = SEC_CMD_STATUS_OK;
input_info(true, &ts->client->dev, "%s: %s\n", __func__, buff);
}
static void set_mis_cal_spec(void *device_data)
{
struct sec_cmd_data *sec = (struct sec_cmd_data *)device_data;
struct sec_ts_data *ts = container_of(sec, struct sec_ts_data, sec);
char buff[16] = { 0 };
char wreg[5] = { 0 };
int ret;
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, true);
sec_cmd_set_default_result(sec);
if (ts->plat_data->mis_cal_check == 0) {
input_err(true, &ts->client->dev,
"%s: [ERROR] not support, %d\n", __func__);
goto NG;
} else if (ts->power_status == SEC_TS_STATE_POWER_OFF) {
input_err(true, &ts->client->dev,
"%s: [ERROR] Touch is stopped\n", __func__);
goto NG;
} else {
if ((sec->cmd_param[0] < 0 || sec->cmd_param[0] > 255) ||
(sec->cmd_param[1] < 0 || sec->cmd_param[1] > 255) ||
(sec->cmd_param[2] < 0 || sec->cmd_param[2] > 255)) {
snprintf(buff, sizeof(buff), "%s", "NG");
goto NG;
} else {
wreg[0] = sec->cmd_param[0];
wreg[1] = sec->cmd_param[1];
wreg[2] = sec->cmd_param[2];
ret = ts->sec_ts_write(ts, SEC_TS_CMD_MIS_CAL_SPEC,
wreg, 3);
if (ret < 0) {
input_err(true, &ts->client->dev,
"%s: nvm write failed. ret: %d\n",
__func__, ret);
goto NG;
} else {
input_info(true, &ts->client->dev,
"%s: tx gap=%d, rx gap=%d, peak=%d\n",
__func__, wreg[0], wreg[1], wreg[2]);
sec_ts_delay(20);
}
}
}
snprintf(buff, sizeof(buff), "%s", "OK");
sec->cmd_state = SEC_CMD_STATUS_OK;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_cmd_set_cmd_exit(sec);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
NG:
snprintf(buff, sizeof(buff), "%s", "NG");
sec->cmd_state = SEC_CMD_STATUS_FAIL;
sec_cmd_set_cmd_result(sec, buff, strnlen(buff, sizeof(buff)));
sec_cmd_set_cmd_exit(sec);
sec_ts_set_bus_ref(ts, SEC_TS_BUS_REF_SYSFS, false);
return;
}