diff options
Diffstat (limited to 'drivers/input/touchscreen/ist30xxa/ist30xx_cmcs.c')
| -rw-r--r-- | drivers/input/touchscreen/ist30xxa/ist30xx_cmcs.c | 1345 |
1 files changed, 1345 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/ist30xxa/ist30xx_cmcs.c b/drivers/input/touchscreen/ist30xxa/ist30xx_cmcs.c new file mode 100644 index 00000000..0b39b20f --- /dev/null +++ b/drivers/input/touchscreen/ist30xxa/ist30xx_cmcs.c @@ -0,0 +1,1345 @@ +/* + * Copyright (C) 2010,Imagis Technology Co. Ltd. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/firmware.h> +#include <linux/stat.h> +#include <linux/uaccess.h> +#include <linux/fcntl.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/err.h> + +#include "ist30xx.h" +#include "ist30xx_update.h" +#include "ist30xx_misc.h" +#include "ist30xx_cmcs.h" + +#if IST30XX_INTERNAL_CMCS_BIN +#include "ist30xx_cmcs_bin.h" +#endif + +#define CMCS_PARSING_DEBUG (0) + +#define CMCS_READY (0) +#define CMCS_NOT_READY (-1) + +#define TSP_CH_UNUSED (0) +#define TSP_CH_SCREEN (1) +#define TSP_CH_KEY (2) +#define TSP_CH_UNKNOWN (-1) + +extern struct ist30xx_data *ts_data; + +int cmcs_ready = CMCS_READY; +u8 *ts_cmcs_bin = NULL; +u32 ts_cmcs_bin_size = 0; +CMCS_BIN_INFO ist30xx_cmcs_bin; +CMCS_BIN_INFO *ts_cmcs = (CMCS_BIN_INFO *)&ist30xx_cmcs_bin; +CMCS_BUF ist30xx_cmcs_buf; +CMCS_BUF *ts_cmcs_buf = (CMCS_BUF *)&ist30xx_cmcs_buf; + + +int ist30xx_parse_cmcs_bin(const u8 *buf, const u32 size) +{ + int ret = -EPERM; + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + memcpy(ts_cmcs->magic1, buf, sizeof(ts_cmcs->magic1)); + memcpy(ts_cmcs->magic2, &buf[size - sizeof(ts_cmcs->magic2)], + sizeof(ts_cmcs->magic2)); + memcpy(cmcs, &buf[sizeof(ts_cmcs->magic1)], sizeof(ts_cmcs->cmcs)); + + if (!strncmp(ts_cmcs->magic1, IST30XX_CMCS_MAGIC, sizeof(ts_cmcs->magic1)) + && !strncmp(ts_cmcs->magic2, IST30XX_CMCS_MAGIC, + sizeof(ts_cmcs->magic2))) { + int idx; + + idx = sizeof(ts_cmcs->magic1) + sizeof(ts_cmcs->cmcs); + ts_cmcs->buf_cmcs = (u8 *)&buf[idx]; + + idx += cmcs->cmd.cmcs_size; + ts_cmcs->buf_sensor = (u32 *)&buf[idx]; + + idx += (cmcs->sensor1_size + cmcs->sensor2_size + cmcs->sensor3_size); + ts_cmcs->buf_node = (u16 *)&buf[idx]; + + ret = 0; + } + + tsp_verb("Magic1: %s, Magic2: %s\n", ts_cmcs->magic1, ts_cmcs->magic2); + tsp_verb(" mode: 0x%x, base(screen: %d, key: %d)\n", + cmcs->cmd.mode, cmcs->cmd.base_screen, cmcs->cmd.base_key); + tsp_verb(" start_cp (cm: %d, cs: %d), vcmp (cm: %d, cs: %d)\n", + cmcs->cmd.start_cp_cm, cmcs->cmd.start_cp_cs, + cmcs->cmd.vcmp_cm, cmcs->cmd.vcmp_cs); + tsp_verb(" timeout: %d\n", cmcs->timeout); + tsp_verb(" baseline scrn: 0x%08x, key: 0x%08x\n", + cmcs->addr.base_screen, cmcs->addr.base_key); + tsp_verb(" start_cp: 0x%08x, vcmp: 0x%08x\n", + cmcs->addr.start_cp, cmcs->addr.vcmp); + tsp_verb(" sensor 1: 0x%08x, 2: 0x%08x, 3: 0x%08x\n", + cmcs->addr.sensor1, cmcs->addr.sensor2, cmcs->addr.sensor3); + tsp_verb(" tx: %d, rx:%d, key rx: %d, num(%d, %d, %d, %d, %d)\n", + cmcs->ch.tx_num, cmcs->ch.rx_num, cmcs->ch.key_rx, cmcs->ch.key1, + cmcs->ch.key2, cmcs->ch.key3, cmcs->ch.key4, cmcs->ch.key5); + tsp_verb(" cr: screen(%4d, %4d), key(%4d, %4d)\n", + cmcs->spec_cr.screen_min, cmcs->spec_cr.screen_max, + cmcs->spec_cr.key_min, cmcs->spec_cr.key_max); + tsp_verb(" cm: screen(%4d, %4d), key(%4d, %4d)\n", + cmcs->spec_cm.screen_min, cmcs->spec_cm.screen_max, + cmcs->spec_cm.key_min, cmcs->spec_cm.key_max); + tsp_verb(" cs0: screen(%4d, %4d), key(%4d, %4d)\n", + cmcs->spec_cs0.screen_min, cmcs->spec_cs0.screen_max, + cmcs->spec_cs0.key_min, cmcs->spec_cs0.key_max); + tsp_verb(" cs1: screen(%4d, %4d), key(%4d, %4d)\n", + cmcs->spec_cs1.screen_min, cmcs->spec_cs1.screen_max, + cmcs->spec_cs1.key_min, cmcs->spec_cs1.key_max); + tsp_verb(" slope - x(%d, %d), y(%d, %d), key(%d, %d)\n", + cmcs->slope.x_min, cmcs->slope.x_max, + cmcs->slope.y_min, cmcs->slope.y_max, + cmcs->slope.key_min, cmcs->slope.key_max); + tsp_verb(" size - cmcs(%d), sensor(%d, %d, %d)\n", + cmcs->cmd.cmcs_size, cmcs->sensor1_size, + cmcs->sensor2_size, cmcs->sensor3_size); + tsp_verb(" checksum - cmcs: 0x%08x, sensor: 0x%08x\n", + cmcs->cmcs_chksum, cmcs->sensor_chksum); + tsp_verb(" cmcs: %x, %x, %x, %x\n", ts_cmcs->buf_cmcs[0], + ts_cmcs->buf_cmcs[1], ts_cmcs->buf_cmcs[2], ts_cmcs->buf_cmcs[3]); + tsp_verb(" sensor: %x, %x, %x, %x\n", + ts_cmcs->buf_sensor[0], ts_cmcs->buf_sensor[1], + ts_cmcs->buf_sensor[2], ts_cmcs->buf_sensor[3]); + tsp_verb(" node: %x, %x, %x, %x\n", + ts_cmcs->buf_node[0], ts_cmcs->buf_node[1], + ts_cmcs->buf_node[2], ts_cmcs->buf_node[3]); + + return ret; +} + +int ist30xx_get_cmcs_info(const u8 *buf, const u32 size) +{ + int ret; + + cmcs_ready = CMCS_NOT_READY; + + ret = ist30xx_parse_cmcs_bin(buf, size); + if (unlikely(ret != TAGS_PARSE_OK)) + tsp_warn("Cannot find tags of CMCS, make a bin by 'cmcs2bin.exe'\n"); + + return ret; +} + +int ist30xx_set_cmcs_sensor(struct i2c_client *client, CMCS_INFO *cmcs, + u32 *buf32) +{ + int i, ret; + int len; + u32 waddr; + u32 *tmp32; + + tsp_verb("%08x %08x %08x %08x\n", buf32[0], buf32[1], buf32[2], buf32[3]); + + waddr = cmcs->addr.sensor1; + len = cmcs->sensor1_size / IST30XX_DATA_LEN; + + for (i = 0; i < len; i++) { + ret = ist30xx_write_cmd(client, waddr, *buf32++); + if (ret) + return ret; + + waddr += IST30XX_DATA_LEN; + } + + tmp32 = buf32; + tsp_verb("%08x %08x %08x %08x\n", tmp32[0], tmp32[1], tmp32[2], tmp32[3]); + + waddr = cmcs->addr.sensor2; + len = (cmcs->sensor2_size - 0x10) / IST30XX_DATA_LEN; + + for (i = 0; i < len; i++) { + ret = ist30xx_write_cmd(client, waddr, *buf32++); + if (ret) + return ret; + + waddr += IST30XX_DATA_LEN; + } + buf32 += (0x10 / IST30XX_DATA_LEN); + + tmp32 = buf32; + tsp_verb("%08x %08x %08x %08x\n", tmp32[0], tmp32[1], tmp32[2], tmp32[3]); + + waddr = cmcs->addr.sensor3; + len = cmcs->sensor3_size / IST30XX_DATA_LEN; + + for (i = 0; i < len; i++) { + ret = ist30xx_write_cmd(client, waddr, *buf32++); + if (ret) + return ret; + + waddr += IST30XX_DATA_LEN; + } + + return 0; +} + +int ist30xx_set_cmcs_cmd(struct i2c_client *client, CMCS_INFO *cmcs) +{ + int ret; + u32 val; + + val = (u32)(cmcs->cmd.base_screen | (cmcs->cmd.mode << 16)); + ret = ist30xx_write_cmd(client, cmcs->addr.base_screen, val); + if (ret) + return ret; + tsp_verb("Baseline screen(0x%08x): 0x%08x\n", cmcs->addr.base_screen, val); + + val = (u32)cmcs->cmd.base_key; + ret = ist30xx_write_cmd(client, cmcs->addr.base_key, val); + if (ret) + return ret; + tsp_verb("Baseline key(0x%08x): 0x%08x\n", cmcs->addr.base_key, val); + + val = cmcs->cmd.start_cp_cm | (cmcs->cmd.start_cp_cs << 16); + ret = ist30xx_write_cmd(client, cmcs->addr.start_cp, val); + if (ret) + return ret; + tsp_verb("StartCP(0x%08x): 0x%08x\n", cmcs->addr.start_cp, val); + + val = cmcs->cmd.vcmp_cm | (cmcs->cmd.vcmp_cs << 16); + ret = ist30xx_write_cmd(client, cmcs->addr.vcmp, val); + if (ret) + return ret; + tsp_verb("VCMP(0x%08x): 0x%08x\n", cmcs->addr.vcmp, val); + + return 0; +} + +int ist30xx_parse_cmcs_buf(CMCS_INFO *cmcs, s16 *buf) +{ + int i, j; + + tsp_info(" %d * %d\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + for (i = 0; i < cmcs->ch.tx_num; i++) { + tsp_info(" "); + for (j = 0; j < cmcs->ch.rx_num; j++) + printk("%5d ", buf[i * cmcs->ch.rx_num + j]); + printk("\n"); + } + + return 0; +} + +int ist30xx_apply_cmcs_slope(CMCS_INFO *cmcs, CMCS_BUF *cmcs_buf) +{ + int i, j; + int idx1, idx2; + int ch_num = cmcs->ch.tx_num * cmcs->ch.rx_num; + int width = cmcs->ch.rx_num; + int height = cmcs->ch.tx_num; + s16 *pcm = (s16 *)cmcs_buf->cm; + s16 *pspec = (s16 *)cmcs_buf->spec; + s16 *pslope0 = (s16 *)cmcs_buf->slope0; + s16 *pslope1 = (s16 *)cmcs_buf->slope1; + + if (cmcs->ch.key_rx) + width -= 1; + else + height -= 1; + + memset(cmcs_buf->slope0, 0, sizeof(cmcs_buf->slope0)); + memset(cmcs_buf->slope1, 0, sizeof(cmcs_buf->slope1)); + + memcpy(cmcs_buf->spec, ts_cmcs->buf_node, (ch_num * sizeof(u16))); + + idx1 = 0; +#if CMCS_PARSING_DEBUG + tsp_info("# Node specific\n"); + for (i = 0; i < cmcs->ch.tx_num; i++) { + tsp_info(" "); + for (j = 0; j < cmcs->ch.rx_num; j++) + printk("%5d ", cmcs_buf->spec[idx1++]); + printk("\n"); + } +#endif + + tsp_verb("# Apply slope0_x\n"); + for (i = 0; i < height; i++) { + for (j = 0; j < width - 1; j++) { + idx1 = (i * cmcs->ch.rx_num) + j; + idx2 = idx1 + 1; + + pslope0[idx1] = (pcm[idx2] - pcm[idx1]); + pslope0[idx1] += (pspec[idx1] - pspec[idx2]); + } + } + + tsp_verb("# Apply slope1_y\n"); + for (i = 0; i < height - 1; i++) { + for (j = 0; j < width; j++) { + idx1 = (i * cmcs->ch.rx_num) + j; + idx2 = idx1 + cmcs->ch.rx_num; + + pslope1[idx1] = (pcm[idx2] - pcm[idx1]); + pslope1[idx1] += (pspec[idx1] - pspec[idx2]); + } + } + +#if CMCS_PARSING_DEBUG + tsp_info("# slope0_x\n"); + for (i = 0; i < height; i++) { + tsp_info(" "); + for (j = 0; j < width; j++) { + idx1 = (i * cmcs->ch.rx_num) + j; + printk("%5d ", pslope0[idx1]); + } + printk("\n"); + } + + tsp_info("# slope1_y\n"); + for (i = 0; i < height; i++) { + tsp_info(" "); + for (j = 0; j < width; j++) { + idx1 = (i * cmcs->ch.rx_num) + j; + printk("%5d ", pslope1[idx1]); + } + printk("\n"); + } +#endif + + return 0; +} + + +int ist30xx_get_cmcs_buf(struct i2c_client *client, CMCS_INFO *cmcs, s16 *buf) +{ + int ret; + u16 len = (IST30XX_CMCS_BUF_SIZE * sizeof(buf[0])) / IST30XX_DATA_LEN; + + ret = ist30xx_read_buf(client, CMD_DEFAULT, (u32 *)buf, len); + if (unlikely(ret)) + return ret; + +#if CMCS_PARSING_DEBUG + ret = ist30xx_parse_cmcs_buf(cmcs, buf); +#endif + + return ret; +} + + +extern int ist30xx_calib_wait(void); +#define cmcs_next_step(ret) { if (unlikely(ret)) goto end; msleep(10); } +int ist30xx_cmcs_test(const u8 *buf, int size) +{ + int ret; + int len; + u32 chksum = 0; + u32 *buf32; + struct i2c_client *client = (struct i2c_client *)ts_data->client; + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + tsp_info("*** CM/CS test ***\n"); + tsp_info(" mode: 0x%x, baseline(screen: %d, key: %d)\n", + cmcs->cmd.mode, cmcs->cmd.base_screen, cmcs->cmd.base_key); + tsp_info(" start_cp (cm: %d, cs: %d), vcmp (cm: %d, cs: %d)\n", + cmcs->cmd.start_cp_cm, cmcs->cmd.start_cp_cs, + cmcs->cmd.vcmp_cm, cmcs->cmd.vcmp_cs); + + ist30xx_disable_irq(ts_data); + + ist30xx_reset(false); + + ret = ist30xx_cmd_reg(client, CMD_ENTER_REG_ACCESS); + cmcs_next_step(ret); + + /* Set sensor register */ + buf32 = ts_cmcs->buf_sensor; + ret = ist30xx_set_cmcs_sensor(client, cmcs, buf32); + cmcs_next_step(ret); + + /* Set command */ + ret = ist30xx_set_cmcs_cmd(client, cmcs); + cmcs_next_step(ret); + + ret = ist30xx_cmd_reg(client, CMD_EXIT_REG_ACCESS); + cmcs_next_step(ret); + + /* Load cmcs test code */ + ret = ist30xx_write_cmd(client, CMD_EXEC_MEM_CODE, 0); + cmcs_next_step(ret); + + buf32 = (u32 *)ts_cmcs->buf_cmcs; + len = cmcs->cmd.cmcs_size / IST30XX_DATA_LEN; + tsp_verb("%08x %08x %08x %08x\n", buf32[0], buf32[1], buf32[2], buf32[3]); + ret = ist30xx_write_buf(client, len, buf32, len); + cmcs_next_step(ret); + + /* Check checksum */ + ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum); + cmcs_next_step(ret); + if (chksum != IST30XX_CMCS_LOAD_END) + goto end; + tsp_info("CM/CS code ready!!\n"); + + /* Check checksum */ + ret = ist30xx_read_cmd(client, CMD_DEFAULT, &chksum); + cmcs_next_step(ret); + tsp_info("CM/CS code chksum: %08x, %08x\n", chksum, cmcs->cmcs_chksum); + + ist30xx_enable_irq(ts_data); + /* Wait CMCS test result */ + if (ist30xx_calib_wait() == 1) + tsp_info("CM/CS test OK.\n"); + else + tsp_info("CM/CS test fail.\n"); + ist30xx_disable_irq(ts_data); + + /* Read CM/CS data*/ + if (ENABLE_CM_MODE(cmcs->cmd.mode)) { + /* Read CM data */ + memset(ts_cmcs_buf->cm, 0, sizeof(ts_cmcs_buf->cm)); + + ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cm); + cmcs_next_step(ret); + + ret = ist30xx_apply_cmcs_slope(cmcs, ts_cmcs_buf); + } + + if (ENABLE_CS_MODE(cmcs->cmd.mode)) { + /* Read CS0 data */ + memset(ts_cmcs_buf->cs0, 0, sizeof(ts_cmcs_buf->cs0)); + memset(ts_cmcs_buf->cs1, 0, sizeof(ts_cmcs_buf->cs1)); + + ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs0); + cmcs_next_step(ret); + + /* Read CS1 data */ + ret = ist30xx_get_cmcs_buf(client, cmcs, ts_cmcs_buf->cs1); + cmcs_next_step(ret); + } + + ist30xx_reset(false); + + ist30xx_start(ts_data); + + cmcs_ready = CMCS_READY; + +end: + if (unlikely(ret)) { + tsp_warn("CM/CS test Fail!, ret=%d\n", ret); + } else if (unlikely(chksum != cmcs->cmcs_chksum)) { + tsp_warn("Error CheckSum: %x(%x)\n", chksum, cmcs->cmcs_chksum); + ret = -ENOEXEC; + } + + ist30xx_enable_irq(ts_data); + + return ret; +} + + +int check_tsp_type(int tx, int rx) +{ + struct CMCS_CH_INFO *ch = (struct CMCS_CH_INFO *)&ts_cmcs->cmcs.ch; + + int last_rx_ch = (int)ch->rx_num - 1; + int last_tx_ch = (int)ch->tx_num - 1; + + if ((rx > last_rx_ch) || (rx < 0) || (tx > last_tx_ch) || (tx < 0)) { + tsp_warn("TSP channel is not correct!! (%d * %d)\n", tx, rx); + return TSP_CH_UNKNOWN; + } + + if (ch->key_rx) { // Key on RX channel + if (rx == last_rx_ch) { + if ((tx == ch->key1) || (tx == ch->key2) || (tx == ch->key3) || + (tx == ch->key4) || (tx == ch->key5)) + return TSP_CH_KEY; + else + return TSP_CH_UNUSED; + } + } // Key on TX channel + else { + if (tx == last_tx_ch) { + if ((rx == ch->key1) || (rx == ch->key2) || (rx == ch->key3) || + (rx == ch->key4) || (rx == ch->key5)) + return TSP_CH_KEY; + else + return TSP_CH_UNUSED; + } + } + + return TSP_CH_SCREEN; +} + +int print_cmcs(s16 *buf16, char *buf) +{ + int i, j; + int idx; + int count = 0; + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + int tx_num = cmcs->ch.tx_num; + int rx_num = cmcs->ch.rx_num; + + for (i = 0; i < tx_num; i++) { + for (j = 0; j < rx_num; j++) { + idx = (i * cmcs->ch.rx_num) + j; + count += sprintf(msg, "%5d ", buf16[idx]); + strcat(buf, msg); + } + + count += sprintf(msg, "\n"); + strcat(buf, msg); + } + + return count; +} + +int print_line_cmcs(int mode, s16 *buf16, char *buf) +{ + int i, j; + int idx; + int type; + int count = 0; + int key_index[5] = { 0, }; + int key_cnt = 0; + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + int tx_num = cmcs->ch.tx_num; + int rx_num = cmcs->ch.rx_num; + + if ((mode == CMCS_FLAG_CM_SLOPE0) || (mode == CMCS_FLAG_CM_SLOPE1)) { + if (cmcs->ch.key_rx) + rx_num--; + else + tx_num--; + } + + for (i = 0; i < tx_num; i++) { + for (j = 0; j < rx_num; j++) { + type = check_tsp_type(i, j); + if ((type == TSP_CH_UNKNOWN) || (type == TSP_CH_UNUSED)) + continue; // Ignore + + if ((mode == CMCS_FLAG_CM_SLOPE0) && (j == (rx_num - 1))) + continue; + else if ((mode == CMCS_FLAG_CM_SLOPE1) && (i == (tx_num - 1))) + continue; + + idx = (i * cmcs->ch.rx_num) + j; + + if (type == TSP_CH_KEY) { + key_index[key_cnt++] = idx; + continue; + } + + count += sprintf(msg, "%5d ", buf16[idx]); + strcat(buf, msg); + } + } + + tsp_info("key cnt: %d\n", key_cnt); + if ((mode != CMCS_FLAG_CM_SLOPE0) && (mode != CMCS_FLAG_CM_SLOPE1)) { + tsp_info("key cnt: %d\n", key_cnt); + for (i = 0; i < key_cnt; i++) { + count += sprintf(msg, "%5d ", buf16[key_index[i]]); + strcat(buf, msg); + } + } + + count += sprintf(msg, "\n"); + strcat(buf, msg); + + return count; +} + +/* sysfs: /sys/class/touch/cmcs/info */ +ssize_t ist30xx_cmcs_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int count; + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if (cmcs == NULL) + return sprintf(buf, "Unknown cmcs bin\n"); + + /* Mode */ + count = sprintf(msg, "%d ", cmcs->cmd.mode); + strcat(buf, msg); + + /* Channel */ + count += sprintf(msg, "%d %d %d %d %d %d %d %d ", + cmcs->ch.tx_num, cmcs->ch.rx_num, cmcs->ch.key_rx, cmcs->ch.key1, + cmcs->ch.key2, cmcs->ch.key3, cmcs->ch.key4, cmcs->ch.key5); + strcat(buf, msg); + + /* Slope */ + count += sprintf(msg, "%d %d %d %d %d %d", + cmcs->slope.x_min, cmcs->slope.x_max, + cmcs->slope.y_min, cmcs->slope.y_max, + cmcs->slope.key_min, cmcs->slope.key_max); + strcat(buf, msg); + + /* CM */ + count += sprintf(msg, "%d %d %d %d ", + cmcs->spec_cm.screen_min, cmcs->spec_cm.screen_max, + cmcs->spec_cm.key_min, cmcs->spec_cm.key_max); + strcat(buf, msg); + + /* CS0 */ + count += sprintf(msg, "%d %d %d %d ", + cmcs->spec_cs0.screen_min, cmcs->spec_cs0.screen_max, + cmcs->spec_cs0.key_min, cmcs->spec_cs0.key_max); + strcat(buf, msg); + + /* CS1 */ + count += sprintf(msg, "%d %d %d %d ", + cmcs->spec_cs1.screen_min, cmcs->spec_cs1.screen_max, + cmcs->spec_cs1.key_min, cmcs->spec_cs1.key_max); + strcat(buf, msg); + + /* CR */ + count += sprintf(msg, "%d %d %d %d ", + cmcs->spec_cr.screen_min, cmcs->spec_cr.screen_max, + cmcs->spec_cr.key_min, cmcs->spec_cr.key_max); + strcat(buf, msg); + + tsp_verb("%s\n", buf); + + return count; +} + +/* sysfs: /sys/class/touch/cmcs/cmcs_binary */ +ssize_t ist30xx_cmcs_binary_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + + if ((ts_cmcs_bin == NULL) || (ts_cmcs_bin_size == 0)) + return sprintf(buf, "Binary is not correct(%d)\n", ts_cmcs_bin_size); + + ist30xx_get_cmcs_info(ts_cmcs_bin, ts_cmcs_bin_size); + + mutex_lock(&ist30xx_mutex); + ret = ist30xx_cmcs_test(ts_cmcs_bin, ts_cmcs_bin_size); + mutex_unlock(&ist30xx_mutex); + + return sprintf(buf, (ret == 0 ? "OK\n" : "Fail\n")); +} + +/* sysfs: /sys/class/touch/cmcs/cmcs_custom */ +ssize_t ist30xx_cmcs_custom_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + int bin_size = 0; + u8 *bin = NULL; + const struct firmware *req_bin = NULL; + + ret = request_firmware(&req_bin, IST30XXB_CMCS_NAME, &ts_data->client->dev); + if (ret) + return sprintf(buf, "File not found, %s\n", IST30XXB_CMCS_NAME); + + bin = (u8 *)req_bin->data; + bin_size = (u32)req_bin->size; + + ist30xx_get_cmcs_info(bin, bin_size); + + mutex_lock(&ist30xx_mutex); + ret = ist30xx_cmcs_test(bin, bin_size); + mutex_unlock(&ist30xx_mutex); + + release_firmware(req_bin); + + tsp_info("size: %d\n", sprintf(buf, (ret == 0 ? "OK\n" : "Fail\n"))); + + return sprintf(buf, (ret == 0 ? "OK\n" : "Fail\n")); +} + +#define MAX_FILE_PATH 255 +/* sysfs: /sys/class/touch/cmcs/cmcs_sdcard */ +ssize_t ist30xx_cmcs_sdcard_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + int bin_size = 0; + u8 *bin = NULL; + const u8 *buff = 0; + mm_segment_t old_fs = { 0 }; + struct file *fp = NULL; + long fsize = 0, nread = 0; + char fw_path[MAX_FILE_PATH]; + + old_fs = get_fs(); + set_fs(get_ds()); + + snprintf(fw_path, MAX_FILE_PATH, "/sdcard/touch/firmware/%s", + IST30XXB_CMCS_NAME); + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + tsp_info("file %s open error:%d\n", fw_path, (s32)fp); + ret = -ENOENT; + goto err_file_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + tsp_info("fail to alloc buffer\n"); + ret = -ENOMEM; + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + tsp_info("mismatch fw size\n"); + + goto err_fw_size; + } + + bin = (u8 *)buff; + bin_size = (u32)fsize; + + filp_close(fp, current->files); + set_fs(old_fs); + tsp_info("firmware is loaded!!\n"); + + ist30xx_get_cmcs_info(bin, bin_size); + + mutex_lock(&ist30xx_mutex); + ret = ist30xx_cmcs_test(bin, bin_size); + mutex_unlock(&ist30xx_mutex); + + kfree(buff); + + tsp_info("size: %d\n", sprintf(buf, (ret == 0 ? "OK\n" : "Fail\n"))); + + return sprintf(buf, (ret == 0 ? "OK\n" : "Fail\n")); + +err_fw_size: + if (buff) + kfree(buff); +err_alloc: + if (fp) + filp_close(fp, NULL); +err_file_open: + set_fs(old_fs); + + return 0; +} + +/* sysfs: /sys/class/touch/cmcs/cm */ +ssize_t ist30xx_cm_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + tsp_verb("CM (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + + return print_cmcs(ts_cmcs_buf->cm, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cm_spec */ +ssize_t ist30xx_cm_spec_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + tsp_verb("CM Spec (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + + return print_cmcs(ts_cmcs_buf->spec, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cm_slope0 */ +ssize_t ist30xx_cm_slope0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + tsp_verb("CM Slope0_X (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + + return print_cmcs(ts_cmcs_buf->slope0, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cm_slope1 */ +ssize_t ist30xx_cm_slope1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + tsp_verb("CM Slope1_Y (%d * %d)\n", + ts_cmcs->cmcs.ch.tx_num, ts_cmcs->cmcs.ch.rx_num); + + return print_cmcs(ts_cmcs_buf->slope1, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cs0 */ +ssize_t ist30xx_cs0_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + tsp_verb("CS0 (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + + return print_cmcs(ts_cmcs_buf->cs0, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cs1 */ +ssize_t ist30xx_cs1_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + tsp_verb("CS1 (%d * %d)\n", cmcs->ch.tx_num, cmcs->ch.rx_num); + + return print_cmcs(ts_cmcs_buf->cs1, buf); +} + + +int print_cm_slope_result(u8 flag, s16 *buf16, char *buf) +{ + int i, j; + int type, idx; + int count = 0, err_cnt = 0; + int min_spec, max_spec; + + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + struct CMCS_SLOPE_INFO *spec = (struct CMCS_SLOPE_INFO *)&cmcs->slope; + + if (flag == CMCS_FLAG_CM_SLOPE0) { + min_spec = spec->x_min; + max_spec = spec->x_max; + } else if (flag == CMCS_FLAG_CM_SLOPE1) { + min_spec = spec->y_min; + max_spec = spec->y_max; + } else { + count = sprintf(msg, "Unknown flag: %d\n", flag); + strcat(buf, msg); + return count; + } + + min_spec *= -1; + + count = sprintf(msg, "Spec: %d ~ %d\n", min_spec, max_spec); + strcat(buf, msg); + + for (i = 0; i < cmcs->ch.tx_num; i++) { + for (j = 0; j < cmcs->ch.rx_num; j++) { + idx = (i * cmcs->ch.rx_num) + j; + + type = check_tsp_type(i, j); + if ((type == TSP_CH_UNKNOWN) || (type == TSP_CH_UNUSED)) + continue; // Ignore + + if ((buf16[idx] > min_spec) && (buf16[idx] < max_spec)) + continue; // OK + + count += sprintf(msg, "%2d,%2d:%4d\n", i, j, buf16[idx]); + strcat(buf, msg); + + err_cnt++; + } + } + + /* Check error count */ + if (err_cnt == 0) + count += sprintf(msg, "OK\n"); + else + count += sprintf(msg, "Fail, node count: %d\n", err_cnt); + strcat(buf, msg); + + return count; +} + +int print_cm_key_slope_result(s16 *buf16, char *buf, bool print) +{ + int i, j; + int type, idx; + int count = 0; + int min_spec, max_spec; + int key_num = 0; + s16 key_cm[5] = { 0, }; + s16 slope_result; + + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + struct CMCS_SLOPE_INFO *spec = (struct CMCS_SLOPE_INFO *)&cmcs->slope; + + min_spec = spec->key_min; + max_spec = spec->key_max; + + min_spec *= -1; + if (print) { + count = sprintf(msg, "Spec: %d ~ %d\n", min_spec, max_spec); + strcat(buf, msg); + } + + for (i = 0; i < cmcs->ch.tx_num; i++) { + for (j = 0; j < cmcs->ch.rx_num; j++) { + idx = (i * cmcs->ch.rx_num) + j; + + type = check_tsp_type(i, j); + if (type == TSP_CH_KEY) + key_cm[key_num++] = buf16[idx]; + } + } + + /* Check key slope */ + slope_result = key_cm[0] - key_cm[1]; + + if (print) { + if ((slope_result > min_spec) && (slope_result < max_spec)) + count += sprintf(msg, "OK (%d)\n", slope_result); + else + count += sprintf(msg, "Fail (%d)\n", slope_result); + } else { + count += sprintf(msg, "%d\n", + (slope_result > 0 ? slope_result : -slope_result)); + } + + strcat(buf, msg); + + return count; +} + +int print_cs_result(s16 *buf16, char *buf, int cs_num) +{ + int i, j; + int type, idx; + int count = 0, err_cnt = 0; + int min_spec, max_spec; + + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + struct CMCS_SPEC_INFO *spec; + + if (cs_num == 0) + spec = (struct CMCS_SPEC_INFO *)&cmcs->spec_cs0; + else + spec = (struct CMCS_SPEC_INFO *)&cmcs->spec_cs1; + + count = sprintf(msg, "Spec: screen(%d~%d), key(%d~%d)\n", + spec->screen_min, spec->screen_max, spec->key_min, spec->key_max); + strcat(buf, msg); + + for (i = 0; i < cmcs->ch.tx_num; i++) { + for (j = 0; j < cmcs->ch.rx_num; j++) { + idx = (i * cmcs->ch.rx_num) + j; + + type = check_tsp_type(i, j); + if ((type == TSP_CH_UNKNOWN) || (type == TSP_CH_UNUSED)) + continue; // Ignore + + if (type == TSP_CH_SCREEN) { + min_spec = spec->screen_min; + max_spec = spec->screen_max; + } else { // TSP_CH_KEY + min_spec = spec->key_min; + max_spec = spec->key_max; + } + + if ((buf16[idx] > min_spec) && (buf16[idx] < max_spec)) + continue; // OK + + count += sprintf(msg, "%2d,%2d:%4d\n", i, j, buf16[idx]); + strcat(buf, msg); + + err_cnt++; + } + } + + /* Check error count */ + if (err_cnt == 0) + count += sprintf(msg, "OK\n"); + else + count += sprintf(msg, "Fail, node count: %d\n", err_cnt); + strcat(buf, msg); + + return count; +} + +/* sysfs: /sys/class/touch/cmcs/cm_result */ +ssize_t ist30xx_cm_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, j; + int type, idx, err_cnt = 0; + int min_spec, max_spec; + int count = 0; + short cm; + char msg[128]; + + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + for (i = 0; i < cmcs->ch.tx_num; i++) { + for (j = 0; j < cmcs->ch.rx_num; j++) { + idx = (i * cmcs->ch.rx_num) + j; + + type = check_tsp_type(i, j); + if ((type == TSP_CH_UNKNOWN) || (type == TSP_CH_UNUSED)) + continue; + + min_spec = max_spec = ts_cmcs_buf->spec[idx]; + if (type == TSP_CH_SCREEN) { + min_spec -= (min_spec * cmcs->spec_cm.screen_min / 100); + max_spec += (min_spec * cmcs->spec_cm.screen_max / 100); + } else { // TSP_CH_KEY + min_spec -= (min_spec * cmcs->spec_cm.key_min / 100); + max_spec += (min_spec * cmcs->spec_cm.key_max / 100); + } + + cm = ts_cmcs_buf->cm[idx]; + if ((cm > min_spec) && (cm < max_spec)) + continue; // OK + + count += sprintf(msg, "%2d,%2d:%4d (%4d~%4d)\n", + i, j, cm, min_spec, max_spec); + strcat(buf, msg); + + err_cnt++; + } + } + + /* Check error count */ + if (err_cnt == 0) + count += sprintf(msg, "OK\n"); + else + count += sprintf(msg, "Fail, node count: %d\n", err_cnt); + strcat(buf, msg); + + return count; +} + +/* sysfs: /sys/class/touch/cmcs/cm_slope0_result */ +ssize_t ist30xx_cm_slope0_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_cm_slope_result(CMCS_FLAG_CM_SLOPE0, + ts_cmcs_buf->slope0, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cm_slope1_result */ +ssize_t ist30xx_cm_slope1_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_cm_slope_result(CMCS_FLAG_CM_SLOPE1, + ts_cmcs_buf->slope1, buf); +} +/* sysfs: /sys/class/touch/cmcs/cm_key_slope_result */ +ssize_t ist30xx_cm_key_slope_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_cm_key_slope_result(ts_cmcs_buf->cm, buf, true); +} + +/* sysfs: /sys/class/touch/cmcs/cs0_result */ +ssize_t ist30xx_cs0_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + return print_cs_result(ts_cmcs_buf->cs0, buf, 0); +} + +/* sysfs: /sys/class/touch/cmcs/cs1_result */ +ssize_t ist30xx_cs1_result_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + return print_cs_result(ts_cmcs_buf->cs1, buf, 1); +} + +/* sysfs: /sys/class/touch/cmcs/line_cm */ +ssize_t ist30xx_line_cm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_line_cmcs(CMCS_FLAG_CM, ts_cmcs_buf->cm, buf); +} + +/* sysfs: /sys/class/touch/cmcs/line_cm_slope0 */ +ssize_t ist30xx_line_cm_slope0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_line_cmcs(CMCS_FLAG_CM_SLOPE0, ts_cmcs_buf->slope0, buf); +} + +/* sysfs: /sys/class/touch/cmcs/line_cm_slope1 */ +ssize_t ist30xx_line_cm_slope1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return 0; + + return print_line_cmcs(CMCS_FLAG_CM_SLOPE1, ts_cmcs_buf->slope1, buf); +} + +/* sysfs: /sys/class/touch/cmcs/line_cs0 */ +ssize_t ist30xx_line_cs0_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + return print_line_cmcs(CMCS_FLAG_CS0, ts_cmcs_buf->cs0, buf); +} + +/* sysfs: /sys/class/touch/cmcs/line_cs1 */ +ssize_t ist30xx_line_cs1_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + CMCS_INFO *cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "CMCS test is not work!!\n"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CS)) + return 0; + + return print_line_cmcs(CMCS_FLAG_CS1, ts_cmcs_buf->cs1, buf); +} + +/* sysfs: /sys/class/touch/cmcs/cm_key_slope_value */ +ssize_t ist30xx_cm_key_slope_value_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + CMCS_INFO *cmcs; + + if ((ts_cmcs_bin == NULL) || (ts_cmcs_bin_size == 0)) + return sprintf(buf, "%s", "FFFF"); + + ist30xx_get_cmcs_info(ts_cmcs_bin, ts_cmcs_bin_size); + + mutex_lock(&ist30xx_mutex); + ret = ist30xx_cmcs_test(ts_cmcs_bin, ts_cmcs_bin_size); + mutex_unlock(&ist30xx_mutex); + + if (ret) + return sprintf(buf, "%s", "FFFF"); + + cmcs = (CMCS_INFO *)&ts_cmcs->cmcs; + + if (cmcs_ready == CMCS_NOT_READY) + return sprintf(buf, "%s", "FFFF"); + + if ((cmcs->cmd.mode) && !(cmcs->cmd.mode & FLAG_ENABLE_CM)) + return sprintf(buf, "%s", "FFFF"); + + return print_cm_key_slope_result(ts_cmcs_buf->cm, buf, false); +} + +/* sysfs : cmcs */ +static DEVICE_ATTR(info, S_IRUGO, ist30xx_cmcs_info_show, NULL); +static DEVICE_ATTR(cmcs_binary, S_IRUGO, ist30xx_cmcs_binary_show, NULL); +static DEVICE_ATTR(cmcs_custom, S_IRUGO, ist30xx_cmcs_custom_show, NULL); +static DEVICE_ATTR(cmcs_sdcard, S_IRUGO, ist30xx_cmcs_sdcard_show, NULL); +static DEVICE_ATTR(cm, S_IRUGO, ist30xx_cm_show, NULL); +static DEVICE_ATTR(cm_spec, S_IRUGO, ist30xx_cm_spec_show, NULL); +static DEVICE_ATTR(cm_slope0, S_IRUGO, ist30xx_cm_slope0_show, NULL); +static DEVICE_ATTR(cm_slope1, S_IRUGO, ist30xx_cm_slope1_show, NULL); +static DEVICE_ATTR(cs0, S_IRUGO, ist30xx_cs0_show, NULL); +static DEVICE_ATTR(cs1, S_IRUGO, ist30xx_cs1_show, NULL); +static DEVICE_ATTR(cm_result, S_IRUGO, ist30xx_cm_result_show, NULL); +static DEVICE_ATTR(cm_slope0_result, S_IRUGO, + ist30xx_cm_slope0_result_show, NULL); +static DEVICE_ATTR(cm_slope1_result, S_IRUGO, + ist30xx_cm_slope1_result_show, NULL); +static DEVICE_ATTR(cm_key_slope_result, S_IRUGO, + ist30xx_cm_key_slope_result_show, NULL); +static DEVICE_ATTR(cs0_result, S_IRUGO, ist30xx_cs0_result_show, NULL); +static DEVICE_ATTR(cs1_result, S_IRUGO, ist30xx_cs1_result_show, NULL); +static DEVICE_ATTR(line_cm, S_IRUGO, ist30xx_line_cm_show, NULL); +static DEVICE_ATTR(line_cm_slope0, S_IRUGO, ist30xx_line_cm_slope0_show, NULL); +static DEVICE_ATTR(line_cm_slope1, S_IRUGO, ist30xx_line_cm_slope1_show, NULL); +static DEVICE_ATTR(line_cs0, S_IRUGO, ist30xx_line_cs0_show, NULL); +static DEVICE_ATTR(line_cs1, S_IRUGO, ist30xx_line_cs1_show, NULL); +static DEVICE_ATTR(cm_key_slope_value, S_IRUGO, + ist30xx_cm_key_slope_value_show, NULL); + +static struct attribute *cmcs_attributes[] = { + &dev_attr_info.attr, + &dev_attr_cmcs_binary.attr, + &dev_attr_cmcs_custom.attr, + &dev_attr_cmcs_sdcard.attr, + &dev_attr_cm.attr, + &dev_attr_cm_spec.attr, + &dev_attr_cm_slope0.attr, + &dev_attr_cm_slope1.attr, + &dev_attr_cs0.attr, + &dev_attr_cs1.attr, + &dev_attr_cm_result.attr, + &dev_attr_cm_slope0_result.attr, + &dev_attr_cm_slope1_result.attr, + &dev_attr_cm_key_slope_result.attr, + &dev_attr_cs0_result.attr, + &dev_attr_cs1_result.attr, + &dev_attr_line_cm.attr, + &dev_attr_line_cm_slope0.attr, + &dev_attr_line_cm_slope1.attr, + &dev_attr_line_cs0.attr, + &dev_attr_line_cs1.attr, + &dev_attr_cm_key_slope_value.attr, + NULL, +}; + +static struct attribute_group cmcs_attr_group = { + .attrs = cmcs_attributes, +}; + +extern struct class *ist30xx_class; +struct device *ist30xx_cmcs_dev; + + +int ist30xx_init_cmcs_sysfs(void) +{ + /* /sys/class/touch/cmcs */ + ist30xx_cmcs_dev = device_create(ist30xx_class, NULL, 0, NULL, "cmcs"); + + /* /sys/class/touch/cmcs/... */ + if (unlikely(sysfs_create_group(&ist30xx_cmcs_dev->kobj, + &cmcs_attr_group))) + tsp_err("Failed to create sysfs group(%s)!\n", "cmcs"); + +#if IST30XX_INTERNAL_CMCS_BIN + ts_cmcs_bin = (u8 *)ist30xxb_cmcs; + ts_cmcs_bin_size = sizeof(ist30xxb_cmcs); + + ist30xx_get_cmcs_info(ts_cmcs_bin, ts_cmcs_bin_size); +#endif + + return 0; +} |
