blob: c8a67f61905c83bc05ced4713e41d6e02437f104 [file] [log] [blame]
/* drivers/input/touchscreen/sec_ts_selftest.c
*
* Copyright (C) 2016 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 <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/regulator/consumer.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/wakelock.h>
#ifdef SAMSUNG_PROJECT
#include <linux/sec_sysfs.h>
#endif
#include <linux/irq.h>
#include <linux/of_gpio.h>
#include <linux/time.h>
#if defined(CONFIG_FB)
#include <linux/fb.h>
#include <linux/notifier.h>
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
#include "sec_ts.h"
#include "sec_ts_selftest.h"
#if SEC_TS_SELFTEST
#define sec_ts_seq_printf(m, fmt, args...) \
do { \
seq_printf(m, fmt, ##args); \
if (!sec_ts_test_result_printed) \
printk(fmt, ##args); \
} while (0)
static uint8_t *sec_ts_report_buf = NULL;
static struct sec_ts_data *ts_data;
static struct proc_dir_entry *android_touch_entry = NULL;
static struct proc_dir_entry *sec_ts_proc_selftest_entry = NULL;
static int8_t sec_ts_test_result_printed = 0;
static int8_t sec_ts_test_result = -1;
void sec_ts_print_report_frame(struct sec_ts_data *ts, u16 *pFrame, bool digit,
bool data16) {
int i = 0;
int j = 0;
unsigned char *pStr = NULL;
unsigned char pTmp[16] = {0};
u16 *pFrame_u16 = (u16 *)pFrame;
u8 *pFrame_u8 = (u8 *)pFrame;
s16 *pFrame_s16 = (s16 *)pFrame;
s8 *pFrame_s8 = (s8 *)pFrame;
pStr = kzalloc(6 * (ts->tx_count + 1), GFP_KERNEL);
if (pStr == NULL)
return;
memset(pStr, 0x0, 6 * (ts->tx_count + 1));
snprintf(pTmp, sizeof(pTmp), " ");
strncat(pStr, pTmp, 6 * ts->tx_count);
for (i = 0; i < ts->tx_count; i++) {
snprintf(pTmp, sizeof(pTmp), "Tx%02d ", i);
strncat(pStr, pTmp, 6 * ts->tx_count);
}
printk("SEC_TS %s\n", pStr);
memset(pStr, 0x0, 6 * (ts->tx_count + 1));
snprintf(pTmp, sizeof(pTmp), " +");
strncat(pStr, pTmp, 6 * ts->tx_count);
for (i = 0; i < ts->tx_count; i++) {
snprintf(pTmp, sizeof(pTmp), "------");
strncat(pStr, pTmp, 6 * ts->rx_count);
}
printk("SEC_TS %s\n", pStr);
for (i = 0; i < ts->rx_count; i++) {
memset(pStr, 0x0, 6 * (ts->tx_count + 1));
snprintf(pTmp, sizeof(pTmp), "Rx%02d | ", i);
strncat(pStr, pTmp, 6 * ts->tx_count);
for (j = 0; j < ts->tx_count; j++) {
if (digit && data16)
snprintf(pTmp, sizeof(pTmp), "%5d ",
pFrame_u16[(j * ts->rx_count) + i]);
else if (!digit && data16)
snprintf(pTmp, sizeof(pTmp), "%5d ",
pFrame_s16[(j * ts->rx_count) + i]);
else if (digit && !data16)
snprintf(pTmp, sizeof(pTmp), "%5d ", pFrame_u8[(j * ts->rx_count) + i]);
else
snprintf(pTmp, sizeof(pTmp), "%5d ", pFrame_s8[(j * ts->rx_count) + i]);
strncat(pStr, pTmp, 6 * ts->rx_count);
}
printk("SEC_TS %s\n", pStr);
}
kfree(pStr);
}
/*******************************************************
Description:
Novatek touchscreen self-test sequence print show
function.
return:
Executive outcomes. 0---succeed.
*******************************************************/
#define SUCCESS 0
#define FAIL -1
static int32_t c_show_selftest(struct seq_file *m, void *v) {
#if 0
struct sec_ts_data *ts = ts_data;
struct selftest_header *st_header;
u8 *ptrBuff = sec_ts_report_buf;
u16 *ptrBuff16 = (u16 *)sec_ts_report_buf;
int i,j;
u8 failcnt = 0;
int result = SUCCESS;
sec_ts_test_result_printed = 0;
printk( "FW Version: %d.%d.%d.%d\n",
ts->plat_data->img_version_of_ic[0],
ts->plat_data->img_version_of_ic[1],
ts->plat_data->img_version_of_ic[2],
ts->plat_data->img_version_of_ic[3]);
st_header = (struct selftest_header *)ptrBuff;
printk( "selftest signature:%08X\n", st_header->signature);
printk( "selftest version:%08X\n", st_header->version);
printk( "selftest total size:%d\n", st_header->totalsize);
printk( "selftest crc32:%08X\n", st_header->crc32);
printk( "selftest result:%08X\n", st_header->result);
printk( "selftest trycnt:%d\n", st_header->trycnt);
printk( "selftest passcnt:%d\n", st_header->passcnt);
printk( "selftest failcnt:%d\n", st_header->failcnt);
ptrBuff += sizeof(struct selftest_header);
ptrBuff += sizeof(u32)*12;
ptrBuff16 = (u16 *)ptrBuff;
printk( "ambient:\n");
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, false, true);
result = SUCCESS;
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
int ratio = ((sec_ts_selftest_ambient[j*ts->rx_count] / 100) * 25);
int min = sec_ts_selftest_ambient[j*ts->rx_count] - ratio;
int max = sec_ts_selftest_ambient[j*ts->rx_count] + ratio;
if ((ptrBuff16[j*ts->rx_count] < min) ||
(ptrBuff16[j*ts->rx_count] > max))
result = FAIL;
}
}
if (result == FAIL) {
printk( "ambient 1st Fail\n");
failcnt++;
}
else
printk( "ambient 1st Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "ambient 2nd:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] < sec_ts_selftest_ambient_2nd[0]) ||
(ptrBuff16[j*ts->rx_count] > sec_ts_selftest_ambient_2nd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "ambient 2nd Fail\n");
failcnt++;
}
else
printk( "ambient 2nd Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "ambient 3rd:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, true, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] < sec_ts_selftest_ambient_3rd[0]) ||
(ptrBuff16[j*ts->rx_count] > sec_ts_selftest_ambient_3rd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "ambient 3rd Fail\n");
failcnt++;
}
else
printk( "ambient 3rd Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "P2P min:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (s16 *)ptrBuff, m, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] < sec_ts_selftest_p2pmin[0]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "P2P Min Fail\n");
failcnt++;
}
else
printk( "P2P Min Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "P2P Max:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, true, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] > sec_ts_selftest_p2pmax[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "P2P Max Fail\n");
failcnt++;
}
else
printk( "P2P Max Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "Raw variance X:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, true, false);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff[j*ts->rx_count] < sec_ts_selftest_rawvarX[0]) ||
(ptrBuff[j*ts->rx_count] > sec_ts_selftest_rawvarX[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "Raw variance X Fail\n");
failcnt++;
}
else
printk( "Raw variance X Pass\n");
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE/2);
ptrBuff16 = (u16 *)ptrBuff;
printk( "Raw variance Y:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, true, false);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff[j*ts->rx_count] < sec_ts_selftest_rawvarY[0]) ||
(ptrBuff[j*ts->rx_count] > sec_ts_selftest_rawvarY[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "Raw variance Y Fail\n");
failcnt++;
}
else
printk( "Raw variance Y Pass\n");
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE/2);
ptrBuff16 = (u16 *)ptrBuff;
printk( "Short :\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] < sec_ts_selftest_short2nd[0]) ||
(ptrBuff16[j*ts->rx_count] > sec_ts_selftest_short2nd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "Short Fail\n");
failcnt++;
}
else
printk( "Short Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "Rawdata:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j*ts->rx_count] < sec_ts_selftest_rawdata[0]) ||
(ptrBuff16[j*ts->rx_count] > sec_ts_selftest_rawdata[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk( "Rawdata Fail\n");
failcnt++;
}
else
printk( "Short Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk( "Offset Cal data:\n");
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, m, true, false);
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE/2);
ptrBuff16 = (u16 *)ptrBuff;
printk( "\n");
#endif
if (sec_ts_test_result < 0) {
sec_ts_seq_printf(m, "%d\n", 0);
} else {
sec_ts_seq_printf(m, "%d\n", 1);
}
sec_ts_test_result_printed = 1;
return 0;
}
/*******************************************************
Description:
Sec touchscreen self-test sequence print start
function.
return:
Executive outcomes. 1---call next function.
NULL---not call next function and sequence loop
stop.
*******************************************************/
static void *c_start(struct seq_file *m, loff_t *pos) {
return *pos < 1 ? (void *)1 : NULL;
}
/*******************************************************
Description:
Sec touchscreen self-test sequence print next
function.
return:
Executive outcomes. NULL---no next and call sequence
stop function.
*******************************************************/
static void *c_next(struct seq_file *m, void *v, loff_t *pos) {
++*pos;
return NULL;
}
/*******************************************************
Description:
Sec touchscreen self-test sequence print stop
function.
return:
n.a.
*******************************************************/
static void c_stop(struct seq_file *m, void *v) { return; }
const struct seq_operations sec_ts_selftest_seq_ops = {
.start = c_start, .next = c_next, .stop = c_stop, .show = c_show_selftest};
static int32_t sec_ts_print_selftest(void) {
struct sec_ts_data *ts = ts_data;
struct selftest_header *st_header;
u8 *ptrBuff = sec_ts_report_buf;
u16 *ptrBuff16 = (u16 *)sec_ts_report_buf;
int i, j;
u8 failcnt = 0;
int result = SUCCESS;
int ratio, min, max;
sec_ts_test_result_printed = 0;
printk("FW Version: %d.%d.%d.%d\n", ts->plat_data->img_version_of_ic[0],
ts->plat_data->img_version_of_ic[1],
ts->plat_data->img_version_of_ic[2],
ts->plat_data->img_version_of_ic[3]);
st_header = (struct selftest_header *)ptrBuff;
printk("selftest signature:%08X\n", st_header->signature);
printk("selftest version:%08X\n", st_header->version);
printk("selftest total size:%d\n", st_header->totalsize);
printk("selftest crc32:%08X\n", st_header->crc32);
printk("selftest result:%08X\n", st_header->result);
printk("selftest trycnt:%d\n", st_header->trycnt);
printk("selftest passcnt:%d\n", st_header->passcnt);
printk("selftest failcnt:%d\n", st_header->failcnt);
ptrBuff += sizeof(struct selftest_header);
ptrBuff += sizeof(u32) * 12;
ptrBuff16 = (u16 *)ptrBuff;
printk("ambient:\n");
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, false, true);
result = SUCCESS;
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
ratio = ((sec_ts_selftest_ambient[j * ts->rx_count] / 100) * 25);
min = sec_ts_selftest_ambient[j * ts->rx_count] - ratio;
max = sec_ts_selftest_ambient[j * ts->rx_count] + ratio;
if ((ptrBuff16[j * ts->rx_count] < min) ||
(ptrBuff16[j * ts->rx_count] > max))
result = FAIL;
}
}
if (result == FAIL) {
printk("ambient 1st Fail\n");
failcnt++;
} else
printk("ambient 1st Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("ambient 2nd:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] < sec_ts_selftest_ambient_2nd[0]) ||
(ptrBuff16[j * ts->rx_count] > sec_ts_selftest_ambient_2nd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("ambient 2nd Fail\n");
failcnt++;
} else
printk("ambient 2nd Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("ambient 3rd:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, true, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] < sec_ts_selftest_ambient_3rd[0]) ||
(ptrBuff16[j * ts->rx_count] > sec_ts_selftest_ambient_3rd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("ambient 3rd Fail\n");
failcnt++;
} else
printk("ambient 3rd Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("P2P min:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (s16 *)ptrBuff, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] < sec_ts_selftest_p2pmin[0]))
result = FAIL;
}
}
if (result == FAIL) {
printk("P2P Min Fail\n");
failcnt++;
} else
printk("P2P Min Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("P2P Max:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, true, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] > sec_ts_selftest_p2pmax[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("P2P Max Fail\n");
failcnt++;
} else
printk("P2P Max Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("Raw variance X:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, true, false);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff[j * ts->rx_count] < sec_ts_selftest_rawvarX[0]) ||
(ptrBuff[j * ts->rx_count] > sec_ts_selftest_rawvarX[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("Raw variance X Fail\n");
failcnt++;
} else
printk("Raw variance X Pass\n");
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE / 2);
ptrBuff16 = (u16 *)ptrBuff;
printk("Raw variance Y:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, true, false);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff[j * ts->rx_count] < sec_ts_selftest_rawvarY[0]) ||
(ptrBuff[j * ts->rx_count] > sec_ts_selftest_rawvarY[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("Raw variance Y Fail\n");
failcnt++;
} else
printk("Raw variance Y Pass\n");
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE / 2);
ptrBuff16 = (u16 *)ptrBuff;
printk("Short :\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] < sec_ts_selftest_short2nd[0]) ||
(ptrBuff16[j * ts->rx_count] > sec_ts_selftest_short2nd[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("Short Fail\n");
failcnt++;
} else
printk("Short Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("Rawdata:\n");
result = SUCCESS;
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, false, true);
for (i = 0; i < ts->rx_count; i++) {
for (j = 0; j < ts->tx_count; j++) {
if ((ptrBuff16[j * ts->rx_count] < sec_ts_selftest_rawdata[0]) ||
(ptrBuff16[j * ts->rx_count] > sec_ts_selftest_rawdata[1]))
result = FAIL;
}
}
if (result == FAIL) {
printk("Rawdata Fail\n");
failcnt++;
} else
printk("Short Pass\n");
ptrBuff += SEC_TS_RAWDATA_MAXSIZE;
ptrBuff16 = (u16 *)ptrBuff;
printk("Offset Cal data:\n");
sec_ts_print_report_frame(ts, (u16 *)ptrBuff, true, false);
ptrBuff += (SEC_TS_RAWDATA_MAXSIZE / 2);
ptrBuff16 = (u16 *)ptrBuff;
/*for (i = 0; i < 8; i++) {
printk( "%d, ", *((u32 *)ptrBuff));
ptrBuff += sizeof(u16);
}*/
printk("\n");
if (failcnt > 0) {
printk("Selftest result Fail\n");
sec_ts_test_result_printed = 1;
return -1;
} else {
printk("Selftest result Pass\n");
sec_ts_test_result_printed = 1;
return 0;
}
}
/*******************************************************
Description:
Sec touchscreen /proc/sec_ts_selftest open function.
return:
Executive outcomes. 0---succeed. negative---failed.
*******************************************************/
static int32_t sec_ts_selftest_open(struct inode *inode, struct file *file) {
struct sec_ts_data *ts = ts_data;
int rc;
u8 tpara = 0x03;
u8 cmd_data[10];
u8 *report_buff;
u32 result_size = SEC_TS_SELFTEST_REPORT_SIZE;
u32 remain_size;
u32 read_size;
disable_irq(ts->client->irq);
input_info(true, &ts->client->dev, "%s: Self test start!\n", __func__);
cmd_data[0] = 0xFF;
rc = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SELFTEST_TYPE, cmd_data, 1);
if (rc < 0) {
input_err(true, &ts->client->dev, "%s: Send selftest cmd failed!\n",
__func__);
goto err_exit;
}
sec_ts_delay(100);
cmd_data[0] = 0x0;
cmd_data[1] = 0x64;
rc = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SELFTEST_PTOP, cmd_data, 4);
if (rc < 0) {
input_err(true, &ts->client->dev, "%s: Send selftest cmd failed!\n",
__func__);
goto err_init;
}
sec_ts_delay(100);
input_info(true, &ts->client->dev, "%s: send selftest cmd!\n", __func__);
rc = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SELFTEST, &tpara, 1);
if (rc < 0) {
input_err(true, &ts->client->dev, "%s: Send selftest cmd failed!\n",
__func__);
goto err_init;
}
sec_ts_delay(1000);
rc = sec_ts_wait_for_ready(ts, SEC_TS_ACK_SELF_TEST_DONE);
if (rc < 0) {
input_err(true, &ts->client->dev, "%s: Selftest execution time out!\n",
__func__);
goto err_init;
}
sec_ts_sw_reset(ts);
sec_ts_delay(500);
input_info(true, &ts->client->dev, "%s: Self test done!\n", __func__);
sec_ts_report_buf = kzalloc(result_size, GFP_KERNEL);
if (!sec_ts_report_buf)
goto err_init;
rc = ts->sec_ts_i2c_write(ts, SEC_TS_READ_SELFTEST_RESULT, NULL, 0);
if (rc < 0) {
input_err(true, &ts->client->dev,
"%s: Send selftest read result cmd failed!\n", __func__);
goto err_exit;
}
report_buff = sec_ts_report_buf;
remain_size = result_size;
read_size = (remain_size > 256) ? (256) : (remain_size);
do {
rc = ts->sec_ts_i2c_read_bulk(ts, report_buff, read_size);
if (rc < 0) {
input_err(true, &ts->client->dev,
"%s: Selftest result read failed remain = %d!\n", __func__,
remain_size);
goto err_exit;
}
remain_size -= read_size;
report_buff += read_size;
read_size = (remain_size > 256) ? 256 : remain_size;
sec_ts_delay(1);
} while (remain_size > 0);
sec_ts_test_result = sec_ts_print_selftest();
enable_irq(ts->client->irq);
if(sec_ts_report_buf)
kfree(sec_ts_report_buf);
return seq_open(file, &sec_ts_selftest_seq_ops);
err_exit:
if(sec_ts_report_buf)
kfree(sec_ts_report_buf);
err_init:
enable_irq(ts->client->irq);
return -1;
}
static const struct file_operations sec_ts_selftest_fops = {
.owner = THIS_MODULE,
.open = sec_ts_selftest_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
/*******************************************************
Description:
Novatek touchscreen MP function proc. file node
initial function.
return:
Executive outcomes. 0---succeed. -1---failed.
*******************************************************/
int32_t sec_ts_test_proc_init(struct sec_ts_data *ts) {
ts_data = ts;
android_touch_entry = proc_mkdir("android_touch", NULL);
if (android_touch_entry == NULL) {
input_err(true, &ts->client->dev, "create /proc/android_touch Failed!\n");
return -1;
}
sec_ts_proc_selftest_entry = proc_create(
"self_test", 0444, android_touch_entry, &sec_ts_selftest_fops);
if (sec_ts_proc_selftest_entry == NULL) {
input_err(true, &ts->client->dev, "create /proc/self_test Failed!\n");
return -1;
} else {
input_info(true, &ts->client->dev, "create /proc/self_test Succeeded!\n");
return 0;
}
}
#endif /* #if SEC_TS_SELFTEST */