summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen/mms134s/mms134s_sec.c
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/input/touchscreen/mms134s/mms134s_sec.c
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/input/touchscreen/mms134s/mms134s_sec.c')
-rw-r--r--drivers/input/touchscreen/mms134s/mms134s_sec.c1000
1 files changed, 1000 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/mms134s/mms134s_sec.c b/drivers/input/touchscreen/mms134s/mms134s_sec.c
new file mode 100644
index 00000000..e578ceed
--- /dev/null
+++ b/drivers/input/touchscreen/mms134s/mms134s_sec.c
@@ -0,0 +1,1000 @@
+static void set_cmd_result(struct mms_fac_data *fac_data, char *buff, int len)
+{
+ strncat(fac_data->cmd_result, buff, len);
+}
+
+static void set_default_result(struct mms_fac_data *fac_data)
+{
+ char delim = ':';
+
+ memset(fac_data->cmd_result, 0x00, ARRAY_SIZE(fac_data->cmd_result));
+ memset(fac_data->cmd_buff, 0x00, ARRAY_SIZE(fac_data->cmd_buff));
+ memcpy(fac_data->cmd_result, fac_data->cmd, strlen(fac_data->cmd));
+ strncat(fac_data->cmd_result, &delim, 1);
+}
+
+static ssize_t show_cmd_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mms_info *info = dev_get_drvdata(dev);
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ char buff[16] = {0,};
+
+ dev_info(&client->dev, "cmd status %d\n", fac_data->cmd_state);
+
+ switch (fac_data->cmd_state) {
+ case CMD_STATUS_WAITING:
+ sprintf(buff, "%s", "WAITING");
+ break;
+ case CMD_STATUS_RUNNING:
+ sprintf(buff, "%s", "RUNNING");
+ break;
+ case CMD_STATUS_OK:
+ sprintf(buff, "%s", "OK");
+ break;
+ case CMD_STATUS_FAIL:
+ sprintf(buff, "%s", "FAIL");
+ break;
+ case CMD_STATUS_NOT_APPLICABLE:
+ sprintf(buff, "%s", "NOT_APPLICABLE");
+ break;
+ default:
+ sprintf(buff, "%s", "NOT_APPLICABLE");
+ break;
+ }
+
+ return sprintf(buf, "%s\n", buff);
+}
+
+static ssize_t show_cmd_result(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mms_info *info = dev_get_drvdata(dev);
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+
+ dev_info(&client->dev, "cmd result %s\n", fac_data->cmd_result);
+
+ mutex_lock(&fac_data->cmd_lock);
+ fac_data->cmd_is_running = false;
+ mutex_unlock(&fac_data->cmd_lock);
+
+ fac_data->cmd_state = CMD_STATUS_WAITING;
+
+ return sprintf(buf, "%s", fac_data->cmd_result);
+}
+
+static int update_from_req_fw(struct mms_info *info)
+{
+ struct i2c_client *client = info->client;
+ const char *path = info->pdata->inkernel_fw_name;
+ const struct firmware *fw;
+ int ret = 0;
+
+ dev_info(&client->dev, "%s : firmware load %s\n", __func__, path);
+
+ ret = request_firmware(&fw, path, &client->dev);
+ if (ret) {
+ dev_err(&client->dev, "Failed to request built-in fw (%d)\n", ret);
+ goto out;
+ }
+
+ ret = mms_flash_fw(fw, info);
+ release_firmware(fw);
+
+out:
+ return ret;
+}
+
+static int update_from_ums(struct mms_info *info)
+{
+ struct i2c_client *client = info->client;
+ const char *path = info->pdata->ums_fw_name;
+ mm_segment_t old_fs;
+ struct file *fp;
+ long fsize, nread;
+ struct firmware fw;
+ u8 *buff;
+ int ret = 0;
+
+ dev_info(&client->dev, "%s : file open %s\n", __func__, path);
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ fp = filp_open(path, O_RDONLY, S_IRUSR);
+ if (IS_ERR(fp)) {
+ dev_err(&client->dev, "Failed to open file\n");
+ ret = PTR_ERR(fp);
+ goto err_file_open;
+ }
+
+ fsize = fp->f_path.dentry->d_inode->i_size;
+
+ buff = kzalloc((size_t)fsize, GFP_KERNEL);
+ if (!buff) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto err_mem_alloc;
+ }
+
+
+ nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos);
+ if (fsize != nread) {
+ dev_err(&client->dev, "Failed to read file correctly\n");
+ ret = -EPERM;
+ goto err_file_read;
+ }
+
+ fw.size = fsize;
+ fw.data = buff;
+ ret = mms_flash_fw(&fw, info);
+
+err_file_read:
+ kfree(buff);
+err_mem_alloc:
+ filp_close(fp, NULL);
+err_file_open:
+ set_fs(old_fs);
+
+ return ret;
+}
+
+static void fw_update(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int fw_type = fac_data->cmd_param[0];
+ int ret;
+
+ set_default_result(fac_data);
+
+ if (!info->enabled) {
+ dev_err(&client->dev, "%s : TSP is disabled\n");
+ goto out;
+ }
+
+ mutex_lock(&info->input_dev->mutex);
+ disable_irq(info->irq);
+
+ switch (fw_type) {
+ case FW_FROM_BUILT_IN:
+ ret = update_from_req_fw(info);
+ break;
+ case FW_FROM_UMS:
+ ret = update_from_ums(info);
+ break;
+ default:
+ dev_err(&client->dev,
+ "%s : Invalid update type(%d)\n", __func__, fw_type);
+ goto err_update;
+ break;
+ }
+
+ if (ret) {
+ dev_err(&client->dev, "%s : Failed fw update(%d)\n", __func__, ret);
+ goto err_update;
+ }
+
+ enable_irq(info->irq);
+ mutex_unlock(&info->input_dev->mutex);
+
+ fac_data->cmd_state = (ret) ? CMD_STATUS_FAIL : CMD_STATUS_OK;
+ sprintf(fac_data->cmd_buff, "%s", (ret) ? "NG" : "OK");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+
+err_update:
+ enable_irq(info->irq);
+ mutex_unlock(&info->input_dev->mutex);
+out:
+ fac_data->cmd_state = CMD_STATUS_FAIL;
+ sprintf(fac_data->cmd_buff, "%s", "NG");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ return;
+}
+
+static void get_threshold(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ u8 buff;
+
+ set_default_result(fac_data);
+
+ buff = i2c_smbus_read_byte_data(info->client, MMS_THRESHOLD);
+ if (buff < 0) {
+ dev_err(&client->dev, "Failed to read threshold (%d)\n", buff);
+ goto out;
+ }
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+ sprintf(fac_data->cmd_buff, "%d", buff);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+
+out:
+ fac_data->cmd_state = FAIL;
+ sprintf(fac_data->cmd_buff, "%s", "NG");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+ return ;
+}
+/*
+static void module_off_master(void *device_data)
+{
+ struct mms_ts_info *info = (struct mms_ts_info *)device_data;
+ struct i2c_client *client = info->client;
+
+ set_default_result(info);
+
+ if (info->pdata->vdd_on)
+ info->pdata->vdd_on(&info->client->dev, 0);
+
+ sprintf(info->cmd_buff, "%s", "OK");
+ set_cmd_result(info, info->cmd_buff, strlen(info->cmd_buff));
+ info->cmd_state = CMD_STATUS_OK;
+
+ dev_info(&client->dev, "%s: \"%s\"(%d)\n", __func__,
+ info->cmd_buff, strlen(info->cmd_buff));
+
+ return;
+}
+
+static void module_on_master(void *device_data)
+{
+ struct mms_ts_info *info = (struct mms_ts_info *)device_data;
+ struct i2c_client *client = info->client;
+
+ set_default_result(info);
+
+ mms_pwr_on_reset(info);
+
+ sprintf(info->cmd_buff, "%s", "OK");
+ set_cmd_result(info, info->cmd_buff, strlen(info->cmd_buff));
+ info->cmd_state = CMD_STATUS_OK;
+
+ dev_info(&client->dev, "%s: \"%s\"(%d)\n", __func__,
+ info->cmd_buff, strlen(info->cmd_buff));
+
+ return;
+}
+*/
+static void get_x_num(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+
+ set_default_result(fac_data);
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+ sprintf(fac_data->cmd_buff, "%d", fac_data->xnode_num);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+}
+
+static void get_y_num(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+
+ set_default_result(fac_data);
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+ sprintf(fac_data->cmd_buff, "%d", fac_data->ynode_num);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+}
+
+static int enter_test_mode(struct mms_info *info)
+{
+ struct i2c_client *client = info->client;
+ int ret = 0;
+
+ disable_irq(info->irq);
+
+ ret = i2c_smbus_write_byte_data(
+ client, MMS_UNIVERSAL_CMD, MMS_UNIV_ENTER_TEST);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to enter test mode(%d)\n", ret);
+ goto out;
+ }
+
+ do {
+ udelay(100);
+ } while (gpio_get_value(info->pdata->gpio_int));
+
+ ret = i2c_smbus_read_byte_data(client, MMS_EVENT_PKT);
+ dev_info(&client->dev, "event(%x)\n", ret);
+
+ if (ret != MMS_TEST_MODE) {
+ dev_err(&client->dev, "Failed to check maker(%x)\n", ret);
+ ret = -EPERM;
+ goto out;
+ }
+
+ return 0;
+
+out:
+ enable_irq(info->irq);
+ return ret;
+}
+
+static int exit_test_mode(struct mms_info *info)
+{
+ struct i2c_client *client = info->client;
+ int ret = 0;
+
+ ret = i2c_smbus_write_byte_data(
+ client, MMS_UNIVERSAL_CMD, MMS_UNIV_EXIT_TEST);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to exit test mode(%d)\n", ret);
+ goto out;
+ }
+
+ enable_irq(info->irq);
+
+ return 0;
+
+out:
+ enable_irq(info->irq);
+
+ return ret;
+}
+
+static int read_cm_data_all(struct mms_info *info, u8 univ_cmd,
+ u8 univ_key_cmd)
+{
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int r, t;
+ int ret = 0;
+ u8 buf[256] = {0, };
+ u8 reg[4] = {0, };
+ s16 cm_data;
+ char data[5];
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ },
+ };
+
+ ret = i2c_smbus_write_byte_data(client, MMS_UNIVERSAL_CMD, univ_cmd);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to send %x cmd(%d)\n",
+ __func__, univ_cmd, ret);
+ goto out;
+ }
+
+ do {
+ udelay(100);
+ } while (gpio_get_value(info->pdata->gpio_int));
+
+ ret = i2c_smbus_read_byte_data(client, MMS_UNIVERSAL_RESULT);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed 0x%x test(%d)\n", __func__,
+ univ_cmd, ret);
+ goto out;
+ }
+
+ msleep(1);
+
+ pr_info("cm_data\n");
+ pr_info("view\n");
+ for (r = 0 ; r < fac_data->xnode_num; r++) {
+ reg[0] = MMS_UNIVERSAL_CMD;
+ reg[1] = univ_cmd + 1; /* get univ_cmd value from node */
+ reg[2] = 0xFF;
+ reg[3] = r;
+ msg[0].len = 4;
+
+ if (i2c_transfer(client->adapter, &msg[0], 1) != 1) {
+ dev_err(&client->dev, "%s : Failed to send cmd for node\n",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ while (gpio_get_value(info->pdata->gpio_int));
+
+ ret = i2c_smbus_read_byte_data(client, MMS_UNIVERSAL_RESULT_SZ);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read node result size\n",
+ __func__);
+ goto out;
+ }
+
+ reg[0] = MMS_UNIVERSAL_RESULT;
+ msg[0].len = 1;
+ msg[1].len = ret;
+ msg[1].buf = buf;
+
+ if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))
+ != ARRAY_SIZE(msg)) {
+ dev_err(&client->dev, "%s : Failed to read node value\n",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ for (t = 0; t < fac_data->ynode_num; t++){
+ cm_data = (s16)(buf[2 * t] | (buf[(2 * t) + 1] << 8));
+ pr_info("%d\n", cm_data);
+ }
+ pr_info("---------\n");
+ }
+
+#if MMS_HAS_TOUCH_KEY
+ pr_info("key\n");
+ if (fac_data->keynode_num) {
+ reg[0] = MMS_UNIVERSAL_CMD;
+ reg[1] = univ_key_cmd;
+ reg[2] = 0xFF;
+ reg[3] = 0x00;
+ msg[0].len = 4;
+
+ if (i2c_transfer(client->adapter, &msg[0],1) != 1) {
+ dev_err(&client->dev, "%s : Failed to send cmd for key\n",
+ __func__);
+ ret = EPERM;
+ goto out;
+ }
+
+ while (gpio_get_value(info->pdata->gpio_int));
+
+ ret = i2c_smbus_read_byte_data(client, MMS_UNIVERSAL_RESULT_SZ);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read key result size\n",
+ __func__);
+ goto out;
+ }
+
+ reg[0] = MMS_UNIVERSAL_RESULT;
+ msg[0].len = 1;
+ msg[1].len = ret;
+ msg[1].buf = buf;
+
+ if(i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))
+ != ARRAY_SIZE(msg)){
+ ret = -EPERM;
+ goto out;
+ }
+
+ for (t = 0; t < fac_data->keynode_num; t++) {
+ cm_data = (s16)(buf[2 * t] | (buf[(2 * t) + 1] << 8));
+ pr_info("%d\n", cm_data);
+ }
+ }
+#endif
+
+out:
+ return ret;
+}
+
+static void run_cm_delta_read(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int ret;
+
+ set_default_result(fac_data);
+
+ ret = enter_test_mode(info);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to enter test mode\n", __func__);
+ goto out;
+ }
+
+ ret = read_cm_data_all(info, MMS_UNIV_CM_DELTA, MMS_UNIV_GET_DELTA_KEY);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read cm data\n", __func__);
+ goto out;
+ }
+
+ ret = exit_test_mode(info);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to exit test mode\n", __func__);
+ goto out;
+ }
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+// sprintf(fac_data->cmd_buff, "%d,%d", raw_min, raw_max);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+
+out:
+ fac_data->cmd_state = CMD_STATUS_FAIL;
+ sprintf(fac_data->cmd_buff, "%s", "NG");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ return;
+}
+
+static void run_cm_abs_read(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int ret;
+
+ set_default_result(fac_data);
+
+ ret = enter_test_mode(info);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to enter test mode\n", __func__);
+ goto out;
+ }
+
+ ret = read_cm_data_all(info, MMS_UNIV_CM_ABS, MMS_UNIV_GET_ABS_KEY);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read cm data\n", __func__);
+ goto out;
+ }
+
+ ret = exit_test_mode(info);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to exit test mode\n", __func__);
+ goto out;
+ }
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+// sprintf(fac_data->cmd_buff, "%d,%d", raw_min, raw_max);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+
+out:
+ fac_data->cmd_state = CMD_STATUS_FAIL;
+ sprintf(fac_data->cmd_buff, "%s", "NG");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ return;
+}
+
+static int read_raw_data_all(struct mms_info *info, u8 univ_cmd)
+{
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int r, t;
+ int ret = 0;
+ u8 buf[42] = {0, };
+ u8 reg[4] = {0, };
+ s16 raw_data;
+ char data[5];
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ },
+ };
+
+ pr_info("raw_data\n");
+ pr_info("view\n");
+ for (r = 0 ; r < fac_data->xnode_num ; r++) {
+ reg[0] = MMS_UNIVERSAL_CMD;
+ reg[1] = univ_cmd;
+ reg[2] = 0xFF;
+ reg[3] = r;
+ msg[0].len = 4;
+
+ msleep(1);
+
+ if (i2c_transfer(client->adapter, &msg[0], 1) != 1) {
+ dev_err(&client->dev, "%s : Failed to send cmd for node\n",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, MMS_UNIVERSAL_RESULT_SZ);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read node result size\n",
+ __func__);
+ goto out;
+ }
+
+ reg[0] = MMS_UNIVERSAL_RESULT;
+ msg[0].len = 1;
+ msg[1].len = ret;
+ msg[1].buf = buf;
+
+ if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))
+ != ARRAY_SIZE(msg)){
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret >>= 1;
+
+ for (t = 0 ; t < ret ; t++) {
+ raw_data = (s16)(buf[2 * t] | (buf[(2 * t) + 1] << 8));
+ pr_info("%d\n", raw_data);
+ }
+ pr_info("---------\n");
+ }
+
+#if MMS_HAS_TOUCH_KEY
+ pr_info("key\n");
+ if (fac_data->keynode_num) {
+ reg[0] = MMS_UNIVERSAL_CMD;
+ reg[1] = univ_cmd + 1; /* univ_cmd for key */
+ reg[2] = 0xFF;
+ reg[3] = 0x00;
+ msg[0].len = 4;
+
+ if (i2c_transfer(client->adapter, &msg[0], 1) != 1) {
+ dev_err(&client->dev, "%s : Failed to send cmd for key\n",
+ __func__);
+ ret = EPERM;
+ goto out;
+ }
+
+ while (gpio_get_value(info->pdata->gpio_int));
+
+ ret = i2c_smbus_read_byte_data(client, MMS_UNIVERSAL_RESULT_SZ);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read key result size\n",
+ __func__);
+ goto out;
+ }
+
+ reg[0] = MMS_UNIVERSAL_RESULT;
+ msg[0].len = 1;
+ msg[1].len = ret;
+ msg[1].buf = buf;
+
+ if (i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg))
+ != ARRAY_SIZE(msg)) {
+ ret = -EPERM;
+ return ret;
+ }
+
+ for (t = 0; t < fac_data->keynode_num; t++){
+ raw_data = (s16)(buf[2 * t] | (buf[(2 * t) + 1] << 8));
+ pr_info("%d\n", raw_data);
+ }
+ }
+#endif
+
+out:
+ return ret;
+}
+
+static void run_intensity_read(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int ret;
+
+ set_default_result(fac_data);
+
+ disable_irq(info->irq);
+
+ ret = read_raw_data_all(info, MMS_UNIV_INTENSITY);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s : Failed to read raw data\n", __func__);
+ goto out;
+ }
+
+ enable_irq(info->irq);
+
+ fac_data->cmd_state = CMD_STATUS_OK;
+// sprintf(fac_data->cmd_buff, "%d,%d", raw_min, raw_max);
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+
+out:
+ enable_irq(info->irq);
+
+ fac_data->cmd_state = CMD_STATUS_FAIL;
+ sprintf(fac_data->cmd_buff, "%s", "NG");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+
+ return;
+}
+
+static void not_support_cmd(void *device_data)
+{
+ struct mms_info *info = (struct mms_info *)device_data;
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+
+ set_default_result(fac_data);
+
+ sprintf(fac_data->cmd_buff, "%s", "NA");
+ set_cmd_result(fac_data, fac_data->cmd_buff, strlen(fac_data->cmd_buff));
+ fac_data->cmd_state = CMD_STATUS_NOT_APPLICABLE;
+ dev_info(&client->dev, "%s : %s\n", __func__, fac_data->cmd_buff);
+
+ return;
+}
+
+#define TSP_CMD(name, func) .cmd_name = name, .cmd_func = func
+
+struct tsp_cmd {
+ struct list_head list;
+ const char *cmd_name;
+ void (*cmd_func)(void *device_data);
+};
+
+struct tsp_cmd tsp_cmds[] = {
+ {TSP_CMD("fw_update", fw_update),},
+/* {TSP_CMD("get_fw_ver_bin", get_fw_ver_bin),},
+ {TSP_CMD("get_fw_ver_ic", get_fw_ver_ic),},
+ {TSP_CMD("get_config_ver", not_support_cmd),},*/
+ {TSP_CMD("get_threshold", get_threshold),},
+ {TSP_CMD("module_off_master", not_support_cmd),},
+ {TSP_CMD("module_on_master", not_support_cmd),},
+ {TSP_CMD("module_off_slave", not_support_cmd),},
+ {TSP_CMD("module_on_slave", not_support_cmd),},
+/* {TSP_CMD("get_chip_vendor", get_chip_vendor),},
+ {TSP_CMD("get_chip_name", get_chip_name),},*/
+ {TSP_CMD("get_x_num", get_x_num),},
+ {TSP_CMD("get_y_num", get_y_num),},
+/* {TSP_CMD("run_reference_read", run_reference_read),},
+ {TSP_CMD("run_inspection_read", run_inspection_read),},*/
+ {TSP_CMD("run_cm_delta_read", run_cm_delta_read),},
+ {TSP_CMD("run_cm_abs_read", run_cm_abs_read),},
+ {TSP_CMD("run_intensity_read", run_intensity_read),},
+/* {TSP_CMD("get_reference", get_reference),},
+ {TSP_CMD("get_cm_abs", get_cm_abs),},
+ {TSP_CMD("get_inspection", get_inspection),},
+ {TSP_CMD("get_cm_delta", get_inspection),},
+ {TSP_CMD("get_intensity", get_intensity),},*/
+ {TSP_CMD("not_support_cmd", not_support_cmd),},
+};
+
+static ssize_t store_cmd(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct mms_info *info = dev_get_drvdata(dev);
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ char *cur, *start, *end;
+ char buff[TSP_CMD_STR_LEN] = {0, };
+ int len, i;
+ struct tsp_cmd *tsp_cmd_ptr = NULL;
+ char delim = ',';
+ bool cmd_found = false;
+ int param_cnt = 0;
+
+ if (!info->enabled) {
+ dev_err(&client->dev, "%s: device is disabled\n", __func__);
+ goto err_out;
+ }
+
+ if (fac_data->cmd_is_running) {
+ dev_err(&client->dev, "%s: other cmd is running\n", __func__);
+ goto err_out;
+ }
+
+ /* check lock */
+ mutex_lock(&fac_data->cmd_lock);
+ fac_data->cmd_is_running = true;
+ mutex_unlock(&fac_data->cmd_lock);
+
+ fac_data->cmd_state = CMD_STATUS_RUNNING;
+
+ for (i = 0; i < ARRAY_SIZE(fac_data->cmd_param); i++)
+ fac_data->cmd_param[i] = 0;
+
+ len = (int)count;
+
+ if (*(buf + len - 1) == '\n')
+ len--;
+
+ memset(fac_data->cmd, 0x00, ARRAY_SIZE(fac_data->cmd));
+ memcpy(fac_data->cmd, buf, len);
+
+ cur = strchr(buf, (int)delim);
+ if (cur)
+ memcpy(buff, buf, cur - buf);
+ else
+ memcpy(buff, buf, len);
+
+ /* find command */
+ list_for_each_entry(tsp_cmd_ptr, &fac_data->cmd_list_head, list) {
+ if (!strcmp(buff, tsp_cmd_ptr->cmd_name)) {
+ cmd_found = true;
+ break;
+ }
+ }
+
+ /* set not_support_cmd */
+ if (!cmd_found) {
+ list_for_each_entry(tsp_cmd_ptr, &fac_data->cmd_list_head, list) {
+ if (!strcmp("not_support_cmd", tsp_cmd_ptr->cmd_name))
+ break;
+ }
+ }
+
+ /* parsing TSP standard tset parameter */
+ if (cur && cmd_found) {
+ cur++;
+ start = cur;
+
+ do {
+ if (*cur == delim || cur - buf == len) {
+ memset(buff, 0x00, ARRAY_SIZE(buff));
+ end = cur;
+ memcpy(buff, start, end - start);
+ *(buff + strlen(buff)) = '\0';
+ kstrtol(buff, 10, fac_data->cmd_param + param_cnt);
+ start = cur + 1;
+ param_cnt++;
+ }
+ cur++;
+ } while (cur - buf <= len);
+ }
+
+ dev_info(&client->dev, "cmd = %s\n", tsp_cmd_ptr->cmd_name);
+
+ for (i = 0; i < param_cnt; i++)
+ dev_info(&client->dev, "cmd param %d = %d\n",
+ i, fac_data->cmd_param[i]);
+
+ tsp_cmd_ptr->cmd_func(info);
+
+err_out:
+ return count;
+}
+
+static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, store_cmd);
+static DEVICE_ATTR(cmd_status, S_IRUGO, show_cmd_status, NULL);
+static DEVICE_ATTR(cmd_result, S_IRUGO, show_cmd_result, NULL);
+
+static struct attribute *touchscreen_attributes[] = {
+ &dev_attr_cmd.attr,
+ &dev_attr_cmd_status.attr,
+ &dev_attr_cmd_result.attr,
+ NULL,
+};
+
+static struct attribute_group touchscreen_attr_group = {
+ .attrs = touchscreen_attributes,
+};
+
+static int get_nodenum(struct mms_info *info)
+{
+ struct mms_fac_data *fac_data = info->fac_data;
+ struct i2c_client *client = info->client;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, MMS_TX_NUM);
+ if (ret <= 0) {
+ dev_err(&client->dev, "Failed to read xnode num(%d)\n", ret);
+ return ret;
+ }
+ fac_data->xnode_num = ret;
+
+ ret = i2c_smbus_read_byte_data(client, MMS_RX_NUM);
+ if (ret <= 0) {
+ dev_err(&client->dev, "Failed to read ynode num(%d)\n", ret);
+ return ret;
+ }
+ fac_data->ynode_num = ret;
+
+ ret = i2c_smbus_read_byte_data(client, MMS_KEY_NUM);
+ if (ret <= 0) {
+ dev_err(&client->dev, "Failed to read keynode num(%d)\n", ret);
+ return ret;
+ }
+ fac_data->keynode_num = ret;
+
+ return 0;
+}
+
+extern struct class *sec_class;
+
+static int init_sec(struct mms_info *info)
+{
+ struct i2c_client *client = info->client;
+ struct mms_fac_data *fac_data;
+ int i;
+ int ret;
+
+ fac_data = kzalloc(sizeof(struct mms_fac_data), GFP_KERNEL);
+ if (!fac_data) {
+ dev_err(&client->dev, "Failed to allocate factory data memory\n");
+ return -ENOMEM;
+ }
+ info->fac_data = fac_data;
+
+ mutex_init(&fac_data->cmd_lock);
+ fac_data->cmd_is_running = false;
+
+ INIT_LIST_HEAD(&fac_data->cmd_list_head);
+ for (i = 0; i < ARRAY_SIZE(tsp_cmds); i++)
+ list_add_tail(&tsp_cmds[i].list, &fac_data->cmd_list_head);
+
+ ret = get_nodenum(info);
+ if (ret) {
+ dev_err(&client->dev, "Failed to read node number(%d)\n", ret);
+ goto err_create_dev_ts;
+ }
+
+/* info->raw_cm_abs = kzalloc(raw_data_size, GFP_KERNEL);
+ info->raw_inspection = kzalloc(raw_data_size, GFP_KERNEL);
+ info->raw_intensity = kzalloc(raw_data_size, GFP_KERNEL);
+ info->raw_reference = kzalloc(raw_data_size, GFP_KERNEL);
+ if (!info->raw_cm_abs || !info->raw_inspection ||
+ !info->raw_intensity || !info->raw_reference) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto err_create_dev_ts;
+ }
+*/
+ fac_data->fac_tsp_dev = device_create(
+ sec_class, NULL, (dev_t)NULL, info, "tsp");
+ if (IS_ERR(fac_data->fac_tsp_dev)) {
+ ret = PTR_ERR(fac_data->fac_tsp_dev);
+ dev_err(&client->dev,
+ "Failed to create device for touch screen (%d)\n", ret);
+ ret = -ENODEV;
+ goto err_create_dev_ts;
+ }
+
+ ret = sysfs_create_group(
+ &fac_data->fac_tsp_dev->kobj, &touchscreen_attr_group);
+ if (ret) {
+ dev_err(&client->dev,
+ "Failed to create sysfs for touch screen (%d)\n", ret);
+ ret = (ret > 0) ? -ret : ret;
+ goto err_create_ts_sysfs;
+ }
+
+ return 0;
+
+err_create_ts_sysfs:
+ device_destroy(sec_class, (dev_t)NULL);
+err_create_dev_ts:
+ kfree(fac_data);
+
+ return ret;
+}
+
+static void destroy_sec(struct mms_info *info)
+{
+ sysfs_remove_group(
+ &info->fac_data->fac_tsp_dev->kobj, &touchscreen_attr_group);
+ device_destroy(sec_class, (dev_t)NULL);
+ kfree(info->fac_data);
+} \ No newline at end of file