linuxOS_D21X/source/linux-5.10/drivers/input/touchscreen/icn81xx/cts_sysfs.c
2024-11-29 16:13:46 +08:00

1243 lines
37 KiB
C

#define LOG_TAG "Sysfs"
#include "cts_config.h"
#include "cts_platform.h"
#include "cts_core.h"
#include "cts_test.h"
#include "cts_firmware.h"
#ifdef CONFIG_CTS_SYSFS
#define MAX_ARG_NUM (100)
#define MAX_ARG_LENGTH (1024)
static char cmdline_param[MAX_ARG_LENGTH + 1];
static int argc;
static char *argv[MAX_ARG_NUM];
static int parse_arg(const char *buf, size_t count)
{
char *p;
memcpy(cmdline_param, buf, min((size_t)MAX_ARG_LENGTH, count));
cmdline_param[count] = '\0';
argc = 0;
p = strim(cmdline_param);
if (p == NULL || p[0] == '\0') {
return 0;
}
while (p && p[0] != '\0' && argc < MAX_ARG_NUM) {
argv[argc++] = strsep(&p, " ,");
}
return argc;
}
/* echo addr value1 value2 value3 ... valueN > write_reg */
static ssize_t write_firmware_register_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 addr;
int i, ret;
u8 *data = NULL;
parse_arg(buf, count);
cts_info("Write firmware register '%.*s'", (int)count, buf);
if (argc < 2) {
cts_err("Too few args %d", argc);
return -EFAULT;
}
ret = kstrtou16(argv[0], 0, &addr);
if (ret) {
cts_err("Invalid address %s", argv[0]);
return -EINVAL;
}
data = (u8 *)kmalloc(argc - 1, GFP_KERNEL);
if (data == NULL) {
cts_err("Allocate buffer for write data failed\n");
return -ENOMEM;
}
for (i = 1; i < argc; i++) {
ret = kstrtou8(argv[i], 0, data + i - 1);
if (ret) {
cts_err("Invalid value %s", argv[i]);
goto free_data;
}
}
ret = cts_fw_reg_writesb(cts_dev, addr, data, argc - 1);
if (ret) {
cts_err("Write firmware register addr: 0x%04x size: %d failed",
addr, argc - 1);
goto free_data;
}
free_data:
kfree(data);
return (ret < 0 ? ret : count);
}
static DEVICE_ATTR(write_reg, S_IWUSR, NULL, write_firmware_register_store);
static ssize_t read_firmware_register_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#define PRINT_ROW_SIZE (16)
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 addr, size, i, remaining;
u8 *data = NULL;
ssize_t count = 0;
int ret = 0;
cts_info("Read firmware register '%.*s'", (int)count, buf);
if (argc != 2) {
return sprintf(buf,
"Invalid num args %d\n"
" 1. echo addr size > read_reg\n"
" 2. cat read_reg\n", argc);
}
ret = kstrtou16(argv[0], 0, &addr);
if (ret) {
return sprintf(buf, "Invalid address: %s\n", argv[0]);
}
ret = kstrtou16(argv[1], 0, &size);
if (ret) {
return sprintf(buf, "Invalid size: %s\n", argv[1]);
}
data = (u8 *)kmalloc(size, GFP_KERNEL);
if (data == NULL) {
return sprintf(buf, "Allocate buffer for read data failed\n");
}
cts_info("Read firmware register from 0x%04x size %u", addr, size);
ret = cts_fw_reg_readsb(cts_dev, addr, data, (size_t)size);
if (ret) {
count = sprintf(buf,
"Read firmware register from 0x%04x size %u failed %d\n",
addr, size, ret);
goto err_free_data;
}
remaining = size;
for (i = 0; i < size && count <= PAGE_SIZE; i += PRINT_ROW_SIZE) {
size_t linelen = min((size_t)remaining, (size_t)PRINT_ROW_SIZE);
remaining -= PRINT_ROW_SIZE;
count += snprintf(buf + count, PAGE_SIZE - count, "%04x: ", addr);
/* Lower version kernel return void */
hex_dump_to_buffer(data + i, linelen, PRINT_ROW_SIZE, 1,
buf + count, PAGE_SIZE - count, true);
count += strlen(buf + count);
if (count < PAGE_SIZE) {
buf[count++] = '\n';
addr += PRINT_ROW_SIZE;
} else {
break;
}
}
err_free_data:
kfree(data);
return count;
#undef PRINT_ROW_SIZE
}
/* echo addr size > read_reg */
static ssize_t read_firmware_register_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
parse_arg(buf, count);
return (argc == 0 ? 0 : count);
}
static DEVICE_ATTR(read_reg, S_IWUSR | S_IRUSR,
read_firmware_register_show, read_firmware_register_store);
static ssize_t curr_firmware_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
int ret = 0;
ret = sprintf(buf,
"Current firmware: \n"
"version: 0x%04x\n"
"Num rows: %u\n"
"Num cols: %u\n"
"X Resolution: %u\n"
"Y Resolution: %u\n"
"hw sensor id: 0x%02x\n"
"fw sensor id: 0x%02x\n"
"sensor id matched: 0x%02x\n",
cts_data->cts_dev.fwdata.version,
cts_data->cts_dev.fwdata.rows,
cts_data->cts_dev.fwdata.cols,
cts_data->cts_dev.fwdata.res_x,
cts_data->cts_dev.fwdata.res_y,
cts_data->cts_dev.confdata.hw_sensor_id,
cts_data->cts_dev.confdata.fw_sensor_id,
cts_data->cts_dev.confdata.is_sensor_matched
);
return ret;
}
static DEVICE_ATTR(curr_ver_info, S_IRUGO, curr_firmware_info_show, NULL);
#ifdef CFG_CTS_DRIVER_BUILTIN_FIRMWARE
static ssize_t driver_builtin_firmware_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i, chip_index, count = 0;
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
chip_index = cts_get_chip_type_index_driver_builtin(cts_dev);
count += snprintf(buf + count, PAGE_SIZE - count,
"Total %d builtin firmware:\n",
cts_get_fw_num_driver_builtin());
for (i = 0; i < cts_get_fw_num_driver_builtin(); i++) {
const struct cts_firmware *firmware =
cts_request_driver_builtin_firmware_by_index(cts_dev, chip_index, i);
if (firmware) {
count += snprintf(buf + count, PAGE_SIZE - count,
"%-2d: sensor_id:%02x hwid:%04x fwid:%04x size:%5zu ver:0x%04x desc: %s\n",
i, cts_get_fw_sensor_id_driver_builtin(chip_index, i),
firmware->hwid, firmware->fwid,
firmware->size, cts_get_fw_version_driver_builtin(firmware),
firmware->name);
} else {
count += snprintf(buf + count, PAGE_SIZE - count,
"%-2d: INVALID\n", i);
}
}
return count;
}
/* echo index/name [flash/sram] > driver_builtin_firmware */
static ssize_t driver_builtin_firmware_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
const struct cts_firmware *firmware;
bool to_flash = true;
int ret, chip_index, fw_index = -1;
parse_arg(buf, count);
if (argc != 1 && argc != 2) {
cts_err("Invalid num args %d\n"
" echo index/name [flash/sram] > driver_builtin_firmware\n", argc);
return -EFAULT;
}
if (isdigit(*argv[0])) {
fw_index = simple_strtoul(argv[0], NULL, 0);
cts_info("firmware index: %d",fw_index);
}else {
cts_err("Invalid firmware index %u", fw_index);
return -EINVAL;
}
if (argc > 1) {
if (strncasecmp(argv[1], "flash", 5) == 0) {
to_flash = true;
} else if (strncasecmp(argv[1], "sram", 4) == 0) {
to_flash = false;
} else {
cts_err("Invalid location '%s', must be 'flash' or 'sram'", argv[1]);
return -EINVAL;
}
}
chip_index = cts_get_chip_type_index_driver_builtin(cts_dev);
cts_info("Update driver builtin firmware '%s' to %s",
argv[1], to_flash ? "flash" : "sram");
if (fw_index >= 0 && fw_index < cts_get_fw_num_driver_builtin()) {
firmware = cts_request_driver_builtin_firmware_by_index(cts_dev, chip_index, fw_index);
} else {
firmware = NULL;//cts_request_driver_builtin_firmware_by_name(buf);
cts_err("Invalid firmware index %u",fw_index);
}
if (firmware) {
ret = cts_stop_device(cts_dev);
if (ret) {
cts_err("Stop device failed %d", ret);
return ret;
}
ret = cts_update_firmware(cts_dev, firmware, to_flash);
if (ret) {
cts_err("Update firmware failed %d", ret);
goto err_start_device;
}
ret = cts_start_device(cts_dev);
if (ret) {
cts_err("Start device failed %d", ret);
return ret;
}
} else {
cts_err("Firmware '%s' NOT found", argv[0]);
return -ENOENT;
}
return count;
err_start_device:
cts_start_device(cts_dev);
return ret;
}
static DEVICE_ATTR(driver_builtin_firmware, S_IWUSR | S_IRUGO,
driver_builtin_firmware_show, driver_builtin_firmware_store);
#endif /* CFG_CTS_DRIVER_BUILTIN_FIRMWARE */
#ifdef CFG_CTS_FIRMWARE_IN_FS
/* echo filepath [flash/sram] > update_firmware_from_file */
static ssize_t update_firmware_from_file_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
const struct cts_firmware *firmware;
bool to_flash = true;
int ret = 0;
// int index;
parse_arg(buf, count);
if (argc > 2) {
cts_err("Invalid num args %d\n"
" echo filepath [flash/sram] > update_from_file\n", argc);
return -EFAULT;
} else if (argc > 1) {
if (strncasecmp(argv[1], "flash", 5) == 0) {
to_flash = true;
} else if (strncasecmp(argv[1], "sram", 4) == 0) {
to_flash = false;
} else {
cts_err("Invalid location '%s', must be 'flash' or 'sram'", argv[1]);
return -EINVAL;
}
}
cts_info("Update firmware from file '%s'", argv[0]);
do_gettimeofday(&start_tv);
//cts_info("update start time>>>>>>>>>>>>> %ldS.%4ldms",start_tv.tv_sec,start_tv.tv_usec/1000);
firmware = cts_request_firmware_from_fs(cts_dev, argv[0]);
if (firmware) {
ret = cts_stop_device(cts_dev);
if (ret) {
cts_err("Stop device failed %d", ret);
return ret;
}
ret = cts_update_firmware(cts_dev, firmware, to_flash);
if (ret) {
cts_err("Update firmware failed %d", ret);
//return ret;
}
ret = cts_start_device(cts_dev);
if (ret) {
cts_err("Start device failed %d", ret);
return ret;
}
do_gettimeofday(&end_tv);
//cts_info("update end time<<<<<<<<<<< %ldS.%4ldms",end_tv.tv_sec,end_tv.tv_usec/1000);
cts_info(">>>>>> update usage time = %4ldms <<<<<<",end_tv.tv_sec*1000+end_tv.tv_usec/1000-start_tv.tv_sec*1000-start_tv.tv_usec/1000);
cts_release_firmware(firmware);
} else {
cts_err("Request firmware from file '%s' failed", argv[0]);
return -ENOENT;
}
return count;
}
static DEVICE_ATTR(update_from_file, S_IWUSR, NULL, update_firmware_from_file_store);
#endif /* CFG_CTS_FIRMWARE_IN_FS */
static ssize_t updating_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "Updating: %s\n",
cts_data->cts_dev.rtdata.updating ? "Y" : "N");
}
static DEVICE_ATTR(updating, S_IRUGO, updating_show, NULL);
static struct attribute *cts_dev_firmware_atts[] = {
&dev_attr_read_reg.attr,
&dev_attr_write_reg.attr,
&dev_attr_curr_ver_info.attr,
// &dev_attr_curr_version.attr,
// &dev_attr_rows.attr,
// &dev_attr_cols.attr,
// &dev_attr_res_x.attr,
// &dev_attr_res_y.attr,
// &dev_attr_esd_protection.attr,
// &dev_attr_monitor_mode.attr,
// &dev_attr_auto_compensate.attr,
#ifdef CFG_CTS_DRIVER_BUILTIN_FIRMWARE
&dev_attr_driver_builtin_firmware.attr,
#endif /* CFG_CTS_DRIVER_BUILTIN_FIRMWARE */
#ifdef CFG_CTS_FIRMWARE_IN_FS
&dev_attr_update_from_file.attr,
#endif /* CFG_CTS_FIRMWARE_IN_FS */
&dev_attr_updating.attr,
NULL
};
static const struct attribute_group cts_dev_firmware_attr_group = {
.name = "firmware",
.attrs = cts_dev_firmware_atts,
};
#if 1
static ssize_t fw_version_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 version = 0;
int ret = 0;
if (argc != 1) {
return sprintf(buf, "Invalid num args %d\n"
"\n"
"example:\n"
"echo 0x1501 > fw_version_test\n"
"cat fw_version_test\n", argc);
}
ret = kstrtou16(argv[0], 0, &version);
if (ret) {
return sprintf(buf, "Invalid version: %s\n", argv[0]);
}
cts_info("fw version test, version = 0x%x", version);
ret = cts_fw_version_test(cts_dev, version);
if (ret) {
return sprintf(buf, "fw version test FAILED %d, version = 0x%x\n",
ret, version);
} else {
return sprintf(buf, "fw version test PASSED, version = 0x%x\n",
version);
}
}
/* echo version > fw_version_test */
static ssize_t fw_version_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
parse_arg(buf, count);
return count;
}
static DEVICE_ATTR(fw_version_test, S_IWUSR | S_IRUGO, fw_version_test_show, fw_version_test_store);
static ssize_t rawdata_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 th_min = 0, th_max = 0;
int ret = 0;
if (argc != 2) {
return sprintf(buf, "Invalid num args %d\n"
"\n"
"example:\n"
"echo 1800 2200 > rawdata_test\n"
"cat rawdata_test\n", argc);
}
ret = kstrtou16(argv[0], 0, &th_min);
if (ret) {
return sprintf(buf, "Invalid threshold_min: %s\n", argv[0]);
}
ret = kstrtou16(argv[1], 0, &th_max);
if (ret) {
return sprintf(buf, "Invalid threshold_max: %s\n", argv[1]);
}
cts_info("Rawdata test, threshold_min = %u threshold_max = %u", th_min, th_max);
ret = cts_rawdata_test(cts_dev, th_min, th_max);
if (ret) {
return sprintf(buf, "Rawdata test FAILED %d, threshold_min = %u threshold_max = %u\n",
ret, th_min, th_max);
} else {
return sprintf(buf, "Rawdata test PASSED, threshold = %u threshold_max = %u\n",
th_min, th_max);
}
}
/* echo th_min th_max > rawdata_test */
static ssize_t rawdata_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
parse_arg(buf, count);
return count;
}
static DEVICE_ATTR(rawdata_test, S_IWUSR | S_IRUGO, rawdata_test_show, rawdata_test_store);
static ssize_t open_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 threshold = 0;
int ret = 0;
if (argc != 1) {
return sprintf(buf, "Invalid num args %d\n"
"\n"
"example:\n"
"echo 800 > open_test\n"
"cat open_test\n", argc);
}
ret = kstrtou16(argv[0], 0, &threshold);
if (ret) {
return sprintf(buf, "Invalid threshold: %s\n", argv[0]);
}
cts_info("Open test, threshold = %u", threshold);
ret = cts_open_test(cts_dev, threshold);
if (ret) {
return sprintf(buf, "Open test FAILED %d, threshold = %u\n",
ret, threshold);
} else {
return sprintf(buf, "Open test PASSED, threshold = %u\n",
threshold);
}
}
/* echo threshod > open_test */
static ssize_t open_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
parse_arg(buf, count);
return count;
}
static DEVICE_ATTR(open_test, S_IWUSR | S_IRUGO, open_test_show, open_test_store);
static ssize_t short_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 threshold = 0;
int ret = 0;
if (argc != 1) {
return sprintf(buf, "Invalid num args %d\n"
"\n"
"example:\n"
"echo 500 > short_test\n"
"cat short_test\n", argc);
}
ret = kstrtou16(argv[0], 0, &threshold);
if (ret) {
return sprintf(buf, "Invalid threshold: %s\n", argv[0]);
}
cts_info("Short test, threshold = %u", threshold);
ret = cts_short_test(cts_dev, threshold);
if (ret) {
return sprintf(buf, "Short test FAILED %d, threshold = %u\n",
ret, threshold);
} else {
return sprintf(buf, "Short test PASSED, threshold = %u\n",
threshold);
}
}
/* echo threshod > short_test */
static ssize_t short_test_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
parse_arg(buf, count);
return count;
}
static DEVICE_ATTR(short_test, S_IWUSR | S_IRUGO,
short_test_show, short_test_store);
static ssize_t testing_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "Testting: %s\n",
cts_data->cts_dev.rtdata.testing ? "Y" : "N");
}
static DEVICE_ATTR(testing, S_IRUGO, testing_show, NULL);
static ssize_t cts_test_all_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
#ifdef SUPPORT_TEST_CFG_FILE
//const char *path = CTS_TEST_CFG_FILE_PATH;
return cts_test(&cts_data->cts_dev, CTS_TEST_CFG_FILE_PATH);
#else
return cts_test(&cts_data->cts_dev, NULL);
#endif
}
static DEVICE_ATTR(cts_test_all, S_IRUGO, cts_test_all_show, NULL);
#ifdef CFG_CTS_HAS_RESET_PIN
static ssize_t reset_test_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
int ret;
int count;
ret = cts_reset_test(cts_dev);
if (ret == 0) {
count = sprintf(buf, "reset pin test sucessful\n");
}
else {
count = sprintf(buf, "reset pin test failed\n");
}
return count;
}
static DEVICE_ATTR(reset_test, S_IRUGO, reset_test_show, NULL);
#endif
static struct attribute *cts_dev_test_atts[] = {
&dev_attr_fw_version_test.attr,
&dev_attr_short_test.attr,
&dev_attr_open_test.attr,
&dev_attr_rawdata_test.attr,
&dev_attr_cts_test_all.attr,
&dev_attr_testing.attr,
#ifdef CFG_CTS_HAS_RESET_PIN
&dev_attr_reset_test.attr,
#endif
NULL
};
static const struct attribute_group cts_dev_test_attr_group = {
.name = "test",
.attrs = cts_dev_test_atts,
};
#endif
static ssize_t ic_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "IC Type : %s\n",
cts_data->cts_dev.hwdata->name);
}
static DEVICE_ATTR(ic_type, S_IRUGO, ic_type_show, NULL);
static ssize_t program_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "Program mode: %s\n",
cts_data->cts_dev.rtdata.program_mode ? "Y" : "N");
}
static ssize_t program_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
parse_arg(buf, count);
if (argc != 1) {
cts_err("Invalid num args %d", argc);
return -EFAULT;
}
if (*argv[0] == '1' || tolower(*argv[0]) == 'y') {
int ret = cts_enter_program_mode(&cts_data->cts_dev);
if (ret) {
cts_err("Enter program mode failed %d", ret);
return ret;
}
}else{
cts_err("Invalid arg value");
}
return count;
}
static DEVICE_ATTR(program_mode, S_IWUSR | S_IRUGO,
program_mode_show, program_mode_store);
static ssize_t normal_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "Normal mode: %s\n",
cts_data->cts_dev.rtdata.program_mode ? "N" : "Y");
}
static ssize_t normal_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
parse_arg(buf, count);
if (argc != 1) {
cts_err("Invalid num args %d", argc);
return -EFAULT;
}
if (*argv[0] == '1' || tolower(*argv[0]) == 'y') {
int ret = cts_enter_normal_mode(&cts_data->cts_dev);
if (ret) {
cts_err("Enter normal mode failed %d", ret);
return ret;
}
}else{
cts_err("Invalid arg value");
}
return count;
}
static DEVICE_ATTR(normal_mode, S_IWUSR | S_IRUGO,
normal_mode_show, normal_mode_store);
static ssize_t device_en_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "is device enabled: %s\n",
cts_is_device_enabled(&cts_data->cts_dev) ? "Y" : "N");
}
static ssize_t device_en_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
parse_arg(buf, count);
if (argc != 1) {
cts_err("Invalid num args %d", argc);
return -EFAULT;
}
if (*argv[0] == '1' || tolower(*argv[0]) == 'y') {
int ret = cts_start_device(&cts_data->cts_dev);
if (ret) {
cts_err("start device fail %d", ret);
return ret;
}
}else if(*argv[0] == '0' || tolower(*argv[0]) == 'n'){
int ret = cts_stop_device(&cts_data->cts_dev);
if (ret) {
cts_err("stop device fail %d", ret);
return ret;
}
}else{
cts_err("Invalid arg value");
}
return count;
}
static DEVICE_ATTR(device_en, S_IWUSR | S_IRUGO,
device_en_show, device_en_store);
#ifdef CONFIG_CTS_ESD_PROTECTION
//cts_enable_esd_protection(cts_data);
static ssize_t esd_check_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
return sprintf(buf, "esd check enabled: %s\n",
cts_data->esd_enabled ? "Y" : "N");
}
static ssize_t esd_check_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
parse_arg(buf, count);
if (argc != 1) {
cts_err("Invalid num args %d", argc);
return -EFAULT;
}
if (*argv[0] == '1' || tolower(*argv[0]) == 'y') {
int ret = cts_enable_esd_protection(cts_data);
if (ret) {
cts_err("enable esd check fail %d", ret);
return ret;
}
}else if(*argv[0] == '0' || tolower(*argv[0]) == 'n'){
int ret = cts_disable_esd_protection(cts_data);
if (ret) {
cts_err("disable esd check fail %d", ret);
return ret;
}
}else{
cts_err("Invalid arg value");
}
return count;
}
static DEVICE_ATTR(esd_check, S_IWUSR | S_IRUGO,
esd_check_show, esd_check_store);
#endif /* CONFIG_CTS_ESD_PROTECTION */
static ssize_t rawdata_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#define RAWDATA_BUFFER_SIZE(cts_dev) \
(cts_dev->fwdata.rows * cts_dev->fwdata.cols * 2)
#define RAWDATA_SELF_CAP_BUFFER_SIZE(cts_dev) \
((cts_dev->fwdata.rows + cts_dev->fwdata.cols) * 2)
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
u16 *rawdata = NULL, *self_cap = NULL;
int ret, r, c, count = 0;
u32 max, min, sum, average;
int max_r, max_c, min_r, min_c;
bool data_valid = true;
cts_info("Show rawdata");
rawdata = (u16 *)kmalloc(RAWDATA_BUFFER_SIZE(cts_dev), GFP_KERNEL);
if (rawdata == NULL) {
cts_err("Allocate memory for rawdata failed\n");
return -ENOMEM;
}
self_cap = (u16 *)kmalloc(RAWDATA_SELF_CAP_BUFFER_SIZE(cts_dev), GFP_KERNEL);
if (self_cap == NULL) {
kfree(rawdata);
cts_err("Allocate memory for rawdata failed\n");
return -ENOMEM;
}
ret = cts_enable_get_rawdata(cts_dev);
if (ret) {
count += sprintf(buf, "Enable read raw data failed %d\n", ret);
goto err_free_rawdata;
}
ret = cts_send_command(cts_dev, CTS_CMD_QUIT_GESTURE_MONITOR);
if (ret) {
count += sprintf(buf, "Send cmd QUIT_GESTURE_MONITOR failed %d\n", ret);
goto err_free_rawdata;
}
msleep(50);
ret = cts_get_rawdata(cts_dev, rawdata);
if(ret) {
count += sprintf(buf, "Get raw data failed %d\n", ret);
data_valid = false;
// Fall through to disable get rawdata
}
ret = cts_get_selfcap_rawdata(cts_dev, self_cap);
if(ret) {
count += sprintf(buf, "Get raw data failed %d\n", ret);
data_valid = false;
// Fall through to disable get rawdata
}
ret = cts_disable_get_rawdata(cts_dev);
if (ret) {
count += sprintf(buf, "Disable read raw data failed %d\n", ret);
// Fall through to show rawdata
}
if (data_valid) {
#define SPLIT_LINE_STR \
"----------------------------------------------------------------------------------------------\n"
#define ROW_NUM_FORMAT_STR "%2d | "
#define COL_NUM_FORMAT_STR " %2u "
#define DATA_FORMAT_STR "%4u "
max = min = rawdata[0];
sum = 0;
max_r = max_c = min_r = min_c = 0;
for (r = 0; r < cts_dev->fwdata.rows; r++) {
for (c = 0; c < cts_dev->fwdata.cols; c++) {
u16 val = rawdata[r * cts_dev->fwdata.cols + c];
sum += val;
if (val > max) {
max = val;
max_r = r;
max_c = c;
} else if (val < min) {
min = val;
min_r = r;
min_c = c;
}
}
}
average = sum / (cts_dev->fwdata.rows * cts_dev->fwdata.cols);
count += sprintf(buf + count,
SPLIT_LINE_STR
"Raw data MIN: [%d][%d]=%u, MAX: [%d][%d]=%u, AVG=%u\n"
SPLIT_LINE_STR
" | ", min_r, min_c, min, max_r, max_c, max, average);
for (c = 0; c < cts_dev->fwdata.cols; c++) {
count += sprintf(buf + count, COL_NUM_FORMAT_STR, c);
}
count += sprintf(buf + count, "\n" SPLIT_LINE_STR);
for (r = 0; r < cts_dev->fwdata.rows && count < PAGE_SIZE; r++) {
count += sprintf(buf + count, ROW_NUM_FORMAT_STR, r);
for (c = 0; c < cts_dev->fwdata.cols && count < PAGE_SIZE; c++) {
count += snprintf(buf + count, PAGE_SIZE - count - 1,
DATA_FORMAT_STR, rawdata[r * cts_dev->fwdata.cols + c]);
}
buf[count++] = '\n';
}
count+= sprintf(buf + count, "\n\nself cap rawdata:\n");
for (r = 0;
r < (cts_dev->fwdata.rows + cts_dev->fwdata.cols)
&& count < PAGE_SIZE;
r++) {
if (r == cts_dev->fwdata.cols) {
buf[count++] = '\n';
}
count += snprintf(buf + count, PAGE_SIZE - count,
DATA_FORMAT_STR, self_cap[r]);
}
buf[count++] = '\n';
#undef SPLIT_LINE_STR
#undef ROW_NUM_FORMAT_STR
#undef COL_NUM_FORMAT_STR
#undef DATA_FORMAT_STR
}
err_free_rawdata:
kfree(rawdata);
kfree(self_cap);
return (data_valid ? count : ret);
#undef RAWDATA_BUFFER_SIZE
#undef RAWDATA_SELF_CAP_BUFFER_SIZE
}
static DEVICE_ATTR(rawdata, S_IRUGO, rawdata_show, NULL);
static ssize_t diffdata_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
#define DIFFDATA_BUFFER_SIZE(cts_dev) \
(cts_dev->fwdata.rows * cts_dev->fwdata.cols * 2)
#define RAWDATA_SELF_CAP_BUFFER_SIZE(cts_dev) \
((cts_dev->fwdata.rows + cts_dev->fwdata.cols) * 2)
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
s16 *diffdata = NULL, *self_cap = NULL;
int ret, r, c, count = 0;
int max, min, sum, average;
int max_r, max_c, min_r, min_c;
bool data_valid = true;
cts_info("Show diffdata");
diffdata = (s16 *)kmalloc(DIFFDATA_BUFFER_SIZE(cts_dev), GFP_KERNEL);
if (diffdata == NULL) {
cts_err("Allocate memory for diffdata failed");
return -ENOMEM;
}
self_cap = (u16 *)kmalloc(RAWDATA_SELF_CAP_BUFFER_SIZE(cts_dev), GFP_KERNEL);
if (self_cap == NULL) {
kfree(diffdata);
cts_err("Allocate memory for rawdata failed\n");
return -ENOMEM;
}
ret = cts_enable_get_rawdata(cts_dev);
if (ret) {
cts_err("Enable read diff data failed %d", ret);
goto err_free_diffdata;
}
ret = cts_send_command(cts_dev, CTS_CMD_QUIT_GESTURE_MONITOR);
if (ret) {
cts_err("Send cmd QUIT_GESTURE_MONITOR failed %d", ret);
goto err_free_diffdata;
}
msleep(50);
ret = cts_get_diffdata(cts_dev, diffdata);
if(ret) {
cts_err("Get diff data failed %d", ret);
data_valid = false;
// Fall through to disable get diffdata
}
ret = cts_get_selfcap_diffdata(cts_dev, self_cap);
if(ret) {
count += sprintf(buf, "Get raw data failed %d\n", ret);
data_valid = false;
// Fall through to disable get rawdata
}
ret = cts_disable_get_rawdata(cts_dev);
if (ret) {
cts_err("Disable read diff data failed %d", ret);
// Fall through to show diffdata
}
if (data_valid) {
#define SPLIT_LINE_STR \
"----------------------------------------------------------------------------------------------\n"
#define ROW_NUM_FORMAT_STR "%2d | "
#define COL_NUM_FORMAT_STR "%4u "
#define DATA_FORMAT_STR "%4d "
max = min = diffdata[0];
sum = 0;
max_r = max_c = min_r = min_c = 0;
for (r = 0; r < cts_dev->fwdata.rows; r++) {
for (c = 0; c < cts_dev->fwdata.cols; c++) {
s16 val = diffdata[r * cts_dev->fwdata.cols + c];
sum += val;
if (val > max) {
max = val;
max_r = r;
max_c = c;
} else if (val < min) {
min = val;
min_r = r;
min_c = c;
}
}
}
average = sum / (cts_dev->fwdata.rows * cts_dev->fwdata.cols);
count += sprintf(buf + count,
SPLIT_LINE_STR
"Diff data MIN: [%d][%d]=%d, MAX: [%d][%d]=%d, AVG=%d\n"
SPLIT_LINE_STR
" | ", min_r, min_c, min, max_r, max_c, max, average);
for (c = 0; c < cts_dev->fwdata.cols; c++) {
count += sprintf(buf + count, COL_NUM_FORMAT_STR, c);
}
count += sprintf(buf + count, "\n" SPLIT_LINE_STR);
for (r = 0; r < cts_dev->fwdata.rows; r++) {
count += sprintf(buf + count, ROW_NUM_FORMAT_STR, r);
for (c = 0; c < cts_dev->fwdata.cols; c++) {
count += snprintf(buf + count, PAGE_SIZE - count,
DATA_FORMAT_STR, diffdata[r * cts_dev->fwdata.cols + c]);
}
buf[count++] = '\n';
}
count+= sprintf(buf + count, "\n\nself cap diffdata:\n");
for (r = 0;
r < (cts_dev->fwdata.rows + cts_dev->fwdata.cols)
&& count < PAGE_SIZE;
r++) {
if (r == cts_dev->fwdata.cols) {
buf[count++] = '\n';
}
count += snprintf(buf + count, PAGE_SIZE - count,
DATA_FORMAT_STR, self_cap[r]);
}
buf[count++] = '\n';
#undef SPLIT_LINE_STR
#undef ROW_NUM_FORMAT_STR
#undef COL_NUM_FORMAT_STR
#undef DATA_FORMAT_STR
}
err_free_diffdata:
kfree(diffdata);
return (data_valid ? count : ret);
#undef DIFFDATA_BUFFER_SIZE
#undef RAWDATA_SELF_CAP_BUFFER_SIZE
}
static DEVICE_ATTR(diffdata, S_IRUGO, diffdata_show, NULL);
#ifdef CFG_CTS_HAS_RESET_PIN
static ssize_t reset_pin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
cts_info("Read RESET-PIN");
return snprintf(buf, PAGE_SIZE,
"Reset pin: %d, status: %d\n",
cts_data->pdata->rst_gpio,
gpio_get_value(cts_data->pdata->rst_gpio));
}
static ssize_t reset_pin_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct cts_device *cts_dev = &cts_data->cts_dev;
cts_info("Write RESET-PIN");
cts_info("Chip staus maybe changed");
cts_plat_set_reset(cts_dev->pdata, (buf[0] == '1') ? 1 : 0);
return count;
}
static DEVICE_ATTR(reset_pin, S_IRUSR | S_IWUSR, reset_pin_show, reset_pin_store);
#endif
static ssize_t irq_pin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
cts_info("Read IRQ-PIN");
return snprintf(buf, PAGE_SIZE,
"IRQ pin: %d, status: %d\n",
cts_data->pdata->int_gpio,
gpio_get_value(cts_data->pdata->int_gpio));
}
static DEVICE_ATTR(irq_pin, S_IRUGO, irq_pin_show, NULL);
static ssize_t irq_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct chipone_ts_data *cts_data = dev_get_drvdata(dev);
struct irq_desc *desc;
cts_info("Read IRQ-INFO");
desc = irq_to_desc(cts_data->pdata->irq);
if (desc == NULL) {
return snprintf(buf, PAGE_SIZE, "IRQ: %d descriptor not found\n",
cts_data->pdata->irq);
}
return snprintf(buf, PAGE_SIZE,
"IRQ num: %d, depth: %u, "
"count: %u, unhandled: %u, last unhandled eslape: %lu\n",
cts_data->pdata->irq, desc->depth,
desc->irq_count, desc->irqs_unhandled, desc->last_unhandled);
}
static DEVICE_ATTR(irq_info, S_IRUGO, irq_info_show, NULL);
static struct attribute *cts_dev_misc_atts[] = {
&dev_attr_ic_type.attr,
&dev_attr_device_en.attr,
&dev_attr_program_mode.attr,
&dev_attr_normal_mode.attr,
&dev_attr_rawdata.attr,
&dev_attr_diffdata.attr,
#ifdef CONFIG_CTS_ESD_PROTECTION
&dev_attr_esd_check.attr,
#endif
#ifdef CFG_CTS_HAS_RESET_PIN
&dev_attr_reset_pin.attr,
#endif
&dev_attr_irq_pin.attr,
&dev_attr_irq_info.attr,
NULL
};
static const struct attribute_group cts_dev_misc_attr_group = {
.name = "misc",
.attrs = cts_dev_misc_atts,
};
static const struct attribute_group *cts_dev_attr_groups[] = {
&cts_dev_firmware_attr_group,
//&cts_dev_flash_attr_group,
&cts_dev_test_attr_group,
&cts_dev_misc_attr_group,
NULL
};
int cts_sysfs_add_device(struct device *dev)
{
int ret = 0, i = 0;
cts_info("Add device attr groups");
// Low version kernel NOT support sysfs_create_groups()
for (i = 0; cts_dev_attr_groups[i]; i++) {
ret = sysfs_create_group(&dev->kobj, cts_dev_attr_groups[i]);
if (ret) {
while (--i >= 0) {
sysfs_remove_group(&dev->kobj, cts_dev_attr_groups[i]);
}
break;
}
}
if (ret) {
cts_err("Add device attr failed %d", ret);
}
ret = sysfs_create_link(NULL, &dev->kobj, "chipone-ts");
if(ret)
{
cts_err("Create sysfs link failed %d", ret);
}
return ret;
}
void cts_sysfs_remove_device(struct device *dev)
{
int i;
cts_info("Remove device attr groups");
sysfs_remove_link(NULL, "chipone-ts");
// Low version kernel NOT support sysfs_remove_groups()
for (i = 0; cts_dev_attr_groups[i]; i++) {
sysfs_remove_group(&dev->kobj, cts_dev_attr_groups[i]);
}
}
#endif /* CONFIG_CTS_SYSFS */