From 9a8a94046a2c6d0c0b762161269596a8c386b503 Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Tue, 25 Jun 2019 13:46:01 -0500 Subject: [PATCH] sec_mmi: plug in mmi interfaces First step to align reference driver's code with MMI requirements Change-Id: I832c7d2927ccd0d04c6ea44548198fe2e54131d3 Signed-off-by: Konstantin Makariev Reviewed-on: https://gerrit.mot.com/1387460 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- drivers/input/touchscreen/sec_mmi/Kbuild | 6 +- drivers/input/touchscreen/sec_mmi/sec_cmd.c | 558 ++++++++++++++++++ drivers/input/touchscreen/sec_mmi/sec_cmd.h | 91 +++ .../input/touchscreen/sec_mmi/sec_custom.h | 14 + drivers/input/touchscreen/sec_mmi/sec_mmi.h | 23 +- drivers/input/touchscreen/sec_mmi/sec_ts.c | 441 ++++++++------ drivers/input/touchscreen/sec_mmi/sec_ts.h | 42 +- drivers/input/touchscreen/sec_mmi/sec_ts_fn.c | 14 +- drivers/input/touchscreen/sec_mmi/sec_ts_fw.c | 2 +- .../input/touchscreen/sec_mmi/sec_ts_mmi.c | 487 ++++++++++----- .../touchscreen/sec_mmi/sec_ts_only_vendor.c | 2 +- 11 files changed, 1325 insertions(+), 355 deletions(-) create mode 100644 drivers/input/touchscreen/sec_mmi/sec_cmd.c create mode 100644 drivers/input/touchscreen/sec_mmi/sec_cmd.h create mode 100644 drivers/input/touchscreen/sec_mmi/sec_custom.h diff --git a/drivers/input/touchscreen/sec_mmi/Kbuild b/drivers/input/touchscreen/sec_mmi/Kbuild index b74db7df16af..e05a7e3c662b 100644 --- a/drivers/input/touchscreen/sec_mmi/Kbuild +++ b/drivers/input/touchscreen/sec_mmi/Kbuild @@ -1,7 +1,9 @@ # add -Wall to try to catch everything we can. EXTRA_CFLAGS += -Wall -EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \ +EXTRA_CFLAGS += \ + -I$(TOP)/motorola/kernel/modules/include \ -I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/sec_mmi obj-m := sec_mmi.o -sec_mmi-objs = sec_ts.o sec_ts_fn.o sec_ts_fw.o sec_ts_only_vendor.o sec_ts_mmi.o \ No newline at end of file +sec_mmi-objs = sec_ts.o sec_ts_fn.o sec_ts_fw.o sec_ts_mmi.o sec_cmd.o +# sec_ts_only_vendor.o diff --git a/drivers/input/touchscreen/sec_mmi/sec_cmd.c b/drivers/input/touchscreen/sec_mmi/sec_cmd.c new file mode 100644 index 000000000000..d856aed0cb58 --- /dev/null +++ b/drivers/input/touchscreen/sec_mmi/sec_cmd.c @@ -0,0 +1,558 @@ +/* + * sec_cmd.c - samsung factory command driver + * + * Copyright (C) 2014 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include "sec_ts.h" + +#if defined USE_SEC_CMD_QUEUE +static void sec_cmd_store_function(struct sec_cmd_data *data); +#endif + +void sec_cmd_set_cmd_exit(struct sec_cmd_data *data) +{ + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + +#ifdef USE_SEC_CMD_QUEUE + mutex_lock(&data->fifo_lock); + if (kfifo_len(&data->cmd_queue)) { + pr_info("%s: do next cmd, left cmd[%d]\n", __func__, + (int)(kfifo_len(&data->cmd_queue) / sizeof(struct command))); + mutex_unlock(&data->fifo_lock); + + /* check lock */ + mutex_lock(&data->cmd_lock); + data->cmd_is_running = true; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = SEC_CMD_STATUS_RUNNING; + sec_cmd_store_function(data); + + } else { + mutex_unlock(&data->fifo_lock); + } +#endif +} + +void sec_cmd_set_default_result(struct sec_cmd_data *data) +{ + char delim = ':'; + memset(data->cmd_result, 0x00, SEC_CMD_RESULT_STR_LEN); + memcpy(data->cmd_result, data->cmd, SEC_CMD_STR_LEN); + strncat(data->cmd_result, &delim, 1); +} + +void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len) +{ + strlcat(data->cmd_result, buff, SEC_CMD_RESULT_STR_LEN); +} + +#ifndef USE_SEC_CMD_QUEUE +static ssize_t sec_cmd_store(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct sec_cmd_data *data = dev_get_drvdata(dev); + char *cur, *start, *end; + char buff[SEC_CMD_STR_LEN] = { 0 }; + int len, i; + struct sec_cmd *sec_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + + if (!data) { + pr_err("%s: No platform data found\n", __func__); + return -EINVAL; + } + + if (strlen(buf) >= SEC_CMD_STR_LEN) { + pr_err("%s: cmd length is over (%s,%d)!!\n", __func__, buf, (int)strlen(buf)); + return -EINVAL; + } + + if (data->cmd_is_running == true) { + pr_err("%s: other cmd is running.\n", __func__); + return -EBUSY; + } + + /* check lock */ + mutex_lock(&data->cmd_lock); + data->cmd_is_running = true; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = SEC_CMD_STATUS_RUNNING; + for (i = 0; i < ARRAY_SIZE(data->cmd_param); i++) + data->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + + memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd)); + memcpy(data->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + pr_debug("%s: COMMAND = %s\n", __func__, buff); + + /* find command */ + list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) { + if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) { + if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name, + SEC_CMD_STR_LEN)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strnlen(buff, ARRAY_SIZE(buff))) = '\0'; + if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0) + goto err_out; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM)); + } + + if (cmd_found) { + pr_info("%s: cmd = %s", __func__, sec_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) { + if (i == 0) + pr_cont(" param ="); + pr_cont(" %d", data->cmd_param[i]); + } + pr_cont("\n"); + } else { + pr_info("%s: cmd = %s(%s)\n", __func__, buff, sec_cmd_ptr->cmd_name); + } + + sec_cmd_ptr->cmd_func(data); + sec_cmd_set_cmd_exit(data); + +err_out: + return count; +} + +#else /* defined USE_SEC_CMD_QUEUE */ +static void sec_cmd_store_function(struct sec_cmd_data *data) +{ + char *cur, *start, *end; + char buff[SEC_CMD_STR_LEN] = { 0 }; + int len, i; + struct sec_cmd *sec_cmd_ptr = NULL; + char delim = ','; + bool cmd_found = false; + int param_cnt = 0; + int ret; + const char *buf; + size_t count; + struct command cmd = {{0}}; + + if (!data) { + pr_err("%s: No platform data found\n", __func__); + return; + } + + mutex_lock(&data->fifo_lock); + if (kfifo_len(&data->cmd_queue)) { + ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command)); + if (!ret) { + pr_err("%s: kfifo_out failed, it seems empty, ret=%d\n", __func__, ret); + mutex_unlock(&data->fifo_lock); + return; + } + } else { + pr_err("%s: left cmd is nothing\n", __func__); + mutex_unlock(&data->fifo_lock); + return; + } + mutex_unlock(&data->fifo_lock); + + buf = cmd.cmd; + count = strlen(buf); + + for (i = 0; i < (int)ARRAY_SIZE(data->cmd_param); i++) + data->cmd_param[i] = 0; + + len = (int)count; + if (*(buf + len - 1) == '\n') + len--; + + memset(data->cmd, 0x00, ARRAY_SIZE(data->cmd)); + memcpy(data->cmd, buf, len); + + cur = strchr(buf, (int)delim); + if (cur) + memcpy(buff, buf, cur - buf); + else + memcpy(buff, buf, len); + + pr_debug("%s: COMMAND : %s\n", __func__, buff); + + /* find command */ + list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) { + if (!strncmp(buff, sec_cmd_ptr->cmd_name, SEC_CMD_STR_LEN)) { + cmd_found = true; + break; + } + } + + /* set not_support_cmd */ + if (!cmd_found) { + list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) { + if (!strncmp("not_support_cmd", sec_cmd_ptr->cmd_name, + SEC_CMD_STR_LEN)) + break; + } + } + + /* parsing parameters */ + if (cur && cmd_found) { + cur++; + start = cur; + memset(buff, 0x00, ARRAY_SIZE(buff)); + + do { + if (*cur == delim || cur - buf == len) { + end = cur; + memcpy(buff, start, end - start); + *(buff + strnlen(buff, ARRAY_SIZE(buff))) = '\0'; + if (kstrtoint(buff, 10, data->cmd_param + param_cnt) < 0) + return; + start = cur + 1; + memset(buff, 0x00, ARRAY_SIZE(buff)); + param_cnt++; + } + cur++; + } while ((cur - buf <= len) && (param_cnt < SEC_CMD_PARAM_NUM)); + } + + if (cmd_found) { + pr_info("%s: cmd = %s", __func__, sec_cmd_ptr->cmd_name); + for (i = 0; i < param_cnt; i++) { + if (i == 0) + pr_cont(" param ="); + pr_cont(" %d", data->cmd_param[i]); + } + pr_cont("\n"); + } else { + pr_info("%s: cmd = %s(%s)\n", __func__, buff, sec_cmd_ptr->cmd_name); + } + + sec_cmd_ptr->cmd_func(data); + +} + +static ssize_t sec_cmd_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sec_cmd_data *data = dev_get_drvdata(dev); + struct command cmd = {{0}}; + int queue_size; + + if (!data) { + pr_err("%s: No platform data found\n", __func__); + return -EINVAL; + } + + if (strlen(buf) >= SEC_CMD_STR_LEN) { + pr_err("%s: cmd length is over (%s,%d)!!\n", __func__, buf, (int)strlen(buf)); + return -EINVAL; + } + + strncpy(cmd.cmd, buf, count); + + mutex_lock(&data->fifo_lock); + queue_size = (kfifo_len(&data->cmd_queue) / sizeof(struct command)); + + if (kfifo_avail(&data->cmd_queue) && (queue_size < SEC_CMD_MAX_QUEUE)) { + kfifo_in(&data->cmd_queue, &cmd, sizeof(struct command)); + pr_info("%s: push cmd: %s\n", __func__, cmd.cmd); + } else { + pr_err("%s: cmd_queue is full!!\n", __func__); + + kfifo_reset(&data->cmd_queue); + pr_err("%s: cmd_queue is reset!!\n", __func__); + mutex_unlock(&data->fifo_lock); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + + return -ENOSPC; + } + + if (data->cmd_is_running == true) { + pr_err("%s: other cmd is running. Wait until previous cmd is done[%d]\n", + __func__, (int)(kfifo_len(&data->cmd_queue) / sizeof(struct command))); + mutex_unlock(&data->fifo_lock); + return -EBUSY; + } + mutex_unlock(&data->fifo_lock); + + /* check lock */ + mutex_lock(&data->cmd_lock); + data->cmd_is_running = true; + mutex_unlock(&data->cmd_lock); + + data->cmd_state = SEC_CMD_STATUS_RUNNING; + sec_cmd_store_function(data); + + return count; +} +#endif + +static ssize_t sec_cmd_show_status(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sec_cmd_data *data = dev_get_drvdata(dev); + char buff[16] = { 0 }; + + if (!data) { + pr_err("%s: No platform data found\n", __func__); + return -EINVAL; + } + + if (data->cmd_state == SEC_CMD_STATUS_WAITING) + snprintf(buff, sizeof(buff), "WAITING"); + + else if (data->cmd_state == SEC_CMD_STATUS_RUNNING) + snprintf(buff, sizeof(buff), "RUNNING"); + + else if (data->cmd_state == SEC_CMD_STATUS_OK) + snprintf(buff, sizeof(buff), "OK"); + + else if (data->cmd_state == SEC_CMD_STATUS_FAIL) + snprintf(buff, sizeof(buff), "FAIL"); + + else if (data->cmd_state == SEC_CMD_STATUS_NOT_APPLICABLE) + snprintf(buff, sizeof(buff), "NOT_APPLICABLE"); + + pr_debug("%s: %d, %s\n", __func__, data->cmd_state, buff); + + return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buff); +} + +static ssize_t sec_cmd_show_result(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sec_cmd_data *data = dev_get_drvdata(dev); + int size; + + if (!data) { + pr_err("%s: No platform data found\n", __func__); + return -EINVAL; + } + + data->cmd_state = SEC_CMD_STATUS_WAITING; + pr_info("%s: %s\n", __func__, data->cmd_result); + size = snprintf(buf, SEC_CMD_RESULT_STR_LEN, "%s\n", data->cmd_result); + + sec_cmd_set_cmd_exit(data); + + return size; +} + +static ssize_t sec_cmd_list_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_cmd_data *data = dev_get_drvdata(dev); + struct sec_cmd *sec_cmd_ptr = NULL; + char buffer[data->cmd_buffer_size + 30]; + char buffer_name[SEC_CMD_STR_LEN]; + + snprintf(buffer, 30, "++factory command list++\n"); + + list_for_each_entry(sec_cmd_ptr, &data->cmd_list_head, list) { + if (strncmp(sec_cmd_ptr->cmd_name, "not_support_cmd", 15)) { + snprintf(buffer_name, SEC_CMD_STR_LEN, "%s\n", sec_cmd_ptr->cmd_name); + strncat(buffer, buffer_name, SEC_CMD_STR_LEN); + } + } + + return snprintf(buf, SEC_CMD_BUF_SIZE, "%s\n", buffer); +} + +static DEVICE_ATTR(cmd, S_IWUSR | S_IWGRP, NULL, sec_cmd_store); +static DEVICE_ATTR(cmd_status, S_IRUGO, sec_cmd_show_status, NULL); +static DEVICE_ATTR(cmd_result, S_IRUGO, sec_cmd_show_result, NULL); +static DEVICE_ATTR(cmd_list, S_IRUGO, sec_cmd_list_show, NULL); + +static struct attribute *sec_fac_attrs[] = { + &dev_attr_cmd.attr, + &dev_attr_cmd_status.attr, + &dev_attr_cmd_result.attr, + &dev_attr_cmd_list.attr, + NULL, +}; + +static struct attribute_group sec_fac_attr_group = { + .attrs = sec_fac_attrs, +}; + +static inline struct device *sec_device_create(struct sec_cmd_data *data, char *dev_name) { + return NULL; +} + +static inline void sec_device_destroy(int devt) { +} + +struct class *sec_class; + +int sec_cmd_init(struct sec_cmd_data *data, struct sec_cmd *cmds, + int len, int devt) +{ + const char *dev_name; + int ret, i; + + sec_class = class_create(THIS_MODULE, "sec_cmd"); + ret = IS_ERR_OR_NULL(sec_class); + if (ret) { + pr_err("%s: fail - class_create\n", __func__); + return -ENODEV; + } + + INIT_LIST_HEAD(&data->cmd_list_head); + + data->cmd_buffer_size = 0; + for (i = 0; i < len; i++) { + list_add_tail(&cmds[i].list, &data->cmd_list_head); + if (cmds[i].cmd_name) + data->cmd_buffer_size += strlen(cmds[i].cmd_name) + 1; + } + + mutex_init(&data->cmd_lock); + + mutex_lock(&data->cmd_lock); + data->cmd_is_running = false; + mutex_unlock(&data->cmd_lock); + +#ifdef USE_SEC_CMD_QUEUE + if (kfifo_alloc(&data->cmd_queue, + SEC_CMD_MAX_QUEUE * sizeof(struct command), GFP_KERNEL)) { + pr_err("%s: failed to alloc queue for cmd\n", __func__); + goto err_alloc_queue; + } + mutex_init(&data->fifo_lock); +#endif + + if (devt == SEC_CLASS_DEVT_TSP) { + dev_name = SEC_CLASS_DEV_NAME_TSP; + + } else if (devt == SEC_CLASS_DEVT_TKEY) { + dev_name = SEC_CLASS_DEV_NAME_TKEY; + + } else if (devt == SEC_CLASS_DEVT_WACOM) { + dev_name = SEC_CLASS_DEV_NAME_WACOM; + + } else { + pr_err("%s: not defined devt=%d\n", __func__, devt); + goto err_get_dev_name; + } + +#ifdef CONFIG_SEC_SYSFS + data->fac_dev = sec_device_create(data, dev_name); +#else + data->fac_dev = device_create(sec_class, NULL, devt, data, dev_name); +#endif + if (IS_ERR(data->fac_dev)) { + pr_err("%s: failed to create device for the sysfs\n", __func__); + goto err_sysfs_device; + } + + dev_set_drvdata(data->fac_dev, data); + + ret = sysfs_create_group(&data->fac_dev->kobj, &sec_fac_attr_group); + if (ret < 0) { + pr_err("%s: failed to create sysfs group\n", __func__); + goto err_sysfs_group; + } + + return 0; + + sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group); +err_sysfs_group: +#ifdef CONFIG_SEC_SYSFS + sec_device_destroy(data->fac_dev->devt); +#else + device_destroy(sec_class, devt); +#endif +err_sysfs_device: +err_get_dev_name: +#ifdef USE_SEC_CMD_QUEUE + mutex_destroy(&data->fifo_lock); + kfifo_free(&data->cmd_queue); +err_alloc_queue: +#endif + mutex_destroy(&data->cmd_lock); + list_del(&data->cmd_list_head); + return -ENODEV; +} + +void sec_cmd_exit(struct sec_cmd_data *data, int devt) +{ +#ifdef USE_SEC_CMD_QUEUE + struct command cmd = {{0}}; + int ret; +#endif + + pr_info("%s", __func__); + sysfs_remove_group(&data->fac_dev->kobj, &sec_fac_attr_group); + dev_set_drvdata(data->fac_dev, NULL); +#ifdef CONFIG_SEC_SYSFS + sec_device_destroy(data->fac_dev->devt); +#else + device_destroy(sec_class, devt); +#endif +#ifdef USE_SEC_CMD_QUEUE + mutex_lock(&data->fifo_lock); + while (kfifo_len(&data->cmd_queue)) { + ret = kfifo_out(&data->cmd_queue, &cmd, sizeof(struct command)); + if (!ret) { + pr_err("%s: kfifo_out failed, it seems empty, ret=%d\n", __func__, ret); + } + pr_info("%s: remove pending commands: %s", __func__, cmd.cmd); + } + mutex_unlock(&data->fifo_lock); + mutex_destroy(&data->fifo_lock); + kfifo_free(&data->cmd_queue); +#endif + mutex_destroy(&data->cmd_lock); + list_del(&data->cmd_list_head); +} + +MODULE_DESCRIPTION("Samsung factory command"); +MODULE_LICENSE("GPL"); + + diff --git a/drivers/input/touchscreen/sec_mmi/sec_cmd.h b/drivers/input/touchscreen/sec_mmi/sec_cmd.h new file mode 100644 index 000000000000..e259c89b61e5 --- /dev/null +++ b/drivers/input/touchscreen/sec_mmi/sec_cmd.h @@ -0,0 +1,91 @@ +#ifndef _SEC_CMD_H_ +#define _SEC_CMD_H_ + +#undef CONFIG_SEC_SYSFS +#undef CONFIG_SEC_FACTORY +#undef USE_SEC_CMD_QUEUE + +#include +#include +#include +#include +#include +#include +#include +#include +#if 0 +#ifdef CONFIG_SEC_SYSFS +//#include +#endif + +#ifndef CONFIG_SEC_FACTORY +#include +#endif + +#ifndef CONFIG_SEC_SYSFS +extern struct class *sec_class; +#endif +#endif +#define SEC_CLASS_DEVT_TSP 10 +#define SEC_CLASS_DEVT_TKEY 11 +#define SEC_CLASS_DEVT_WACOM 12 + +#define SEC_CLASS_DEV_NAME_TSP "tsp" +#define SEC_CLASS_DEV_NAME_TKEY "sec_touchkey" +#define SEC_CLASS_DEV_NAME_WACOM "sec_epen" + +#define SEC_CMD(name, func) .cmd_name = name, .cmd_func = func + +#define SEC_CMD_BUF_SIZE (4096 - 1) +#define SEC_CMD_STR_LEN 256 +#define SEC_CMD_RESULT_STR_LEN (4096 - 1) +#define SEC_CMD_PARAM_NUM 8 + +struct sec_cmd { + struct list_head list; + const char *cmd_name; + void (*cmd_func)(void *device_data); +}; + +enum SEC_CMD_STATUS { + SEC_CMD_STATUS_WAITING = 0, + SEC_CMD_STATUS_RUNNING, // = 1 + SEC_CMD_STATUS_OK, // = 2 + SEC_CMD_STATUS_FAIL, // = 3 + SEC_CMD_STATUS_NOT_APPLICABLE, // = 4 +}; + +#ifdef USE_SEC_CMD_QUEUE +#define SEC_CMD_MAX_QUEUE 10 + +struct command { + char cmd[SEC_CMD_STR_LEN]; +}; +#endif + +struct sec_cmd_data { + struct device *fac_dev; + struct list_head cmd_list_head; + u8 cmd_state; + char cmd[SEC_CMD_STR_LEN]; + int cmd_param[SEC_CMD_PARAM_NUM]; + char cmd_result[SEC_CMD_RESULT_STR_LEN]; + int cmd_buffer_size; + bool cmd_is_running; + struct mutex cmd_lock; +#ifdef USE_SEC_CMD_QUEUE + struct kfifo cmd_queue; + struct mutex fifo_lock; +#endif +}; + +extern void sec_cmd_set_cmd_exit(struct sec_cmd_data *data); +extern void sec_cmd_set_default_result(struct sec_cmd_data *data); +extern void sec_cmd_set_cmd_result(struct sec_cmd_data *data, char *buff, int len); +extern int sec_cmd_init(struct sec_cmd_data *data, + struct sec_cmd *cmds, int len, int devt); +extern void sec_cmd_exit(struct sec_cmd_data *data, int devt); + +#endif /* _SEC_CMD_H_ */ + + diff --git a/drivers/input/touchscreen/sec_mmi/sec_custom.h b/drivers/input/touchscreen/sec_mmi/sec_custom.h new file mode 100644 index 000000000000..9b12c82e8de6 --- /dev/null +++ b/drivers/input/touchscreen/sec_mmi/sec_custom.h @@ -0,0 +1,14 @@ +#ifndef _SEC_CUSTOM_H_ +#define _SEC_CUSTOM_H_ +/* ABS_MT */ +#define ABS_MT_CUSTOM 0x3e +/* SW_ */ +#define SW_GLOVE 0x0f +/* KEY_ */ +#define KEY_SIDE_GESTURE 0x1c6 +#define KEY_BLACK_UI_GESTURE 0x1c7 +#define KEY_SIDE_GESTURE_RIGHT 0x1ca +#define KEY_SIDE_GESTURE_LEFT 0x1cb +#endif /* _SEC_CUSTOM_H_ */ + + diff --git a/drivers/input/touchscreen/sec_mmi/sec_mmi.h b/drivers/input/touchscreen/sec_mmi/sec_mmi.h index cc94c6110851..d20828a2207d 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_mmi.h +++ b/drivers/input/touchscreen/sec_mmi/sec_mmi.h @@ -4,22 +4,43 @@ #include #include #include + +#if defined(CONFIG_DRM) #include +extern bool dsi_display_is_panel_enable(int id, int *probe_status, char **pname); +#endif #define TSDEV_MINOR_BASE 128 #define TSDEV_MINOR_MAX 32 +struct sec_ts_data; + struct sec_mmi_data { + struct sec_ts_data *ts_ptr; struct i2c_client *i2c_client; struct device *ts_class_dev; struct notifier_block panel_nb; - struct work_struct resume_work; + struct delayed_work resume_work; + struct delayed_work detection_work; int ctrl_dsi; + unsigned int build_id; + unsigned int config_id; + char product_id[10]; char *image_name; const char *class_entry_name; const char *bound_display; + + void (*hard_reset)(struct sec_mmi_data *data); }; +int sec_mmi_data_init(struct sec_ts_data *ts, bool enable); + +#define DEV_MMI (&data->i2c_client->dev) +#define DEV_TS (&ts->client->dev) + +extern struct class *get_touchscreen_class_ptr(void); +extern void set_touchscreen_class_ptr(struct class *ptr); + #endif diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts.c b/drivers/input/touchscreen/sec_mmi/sec_ts.c index bd538b7f025b..018388762bb2 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts.c @@ -13,6 +13,7 @@ struct sec_ts_data *tsp_info; #include "sec_ts.h" +#include "sec_mmi.h" struct sec_ts_data *ts_dup; @@ -26,8 +27,18 @@ static int sec_ts_input_open(struct input_dev *dev); static void sec_ts_input_close(struct input_dev *dev); #endif -int sec_ts_read_information(struct sec_ts_data *ts); - +void sec_ts_irq_enable(struct sec_ts_data *ts, bool on) +{ + if (on) { + if (ts->irq_enabled) + return; + ts->irq_enabled = true; + enable_irq(ts->client->irq); + } else if (ts->irq_enabled) { + ts->irq_enabled = false; + disable_irq(ts->client->irq); + } +} int sec_ts_i2c_write(struct sec_ts_data *ts, u8 reg, u8 *data, int len) { @@ -350,17 +361,17 @@ static void sec_ts_check_rawdata(struct work_struct *work) static void dump_tsp_log(void) { - pr_info("%s: %s %s: start\n", SEC_TS_I2C_NAME, SECLOG, __func__); + pr_info("%s: %s: start\n", SEC_TS_I2C_NAME, __func__); #ifdef CONFIG_BATTERY_SAMSUNG if (lpcharge == 1) { - pr_err("%s: %s %s: ignored ## lpm charging Mode!!\n", SEC_TS_I2C_NAME, SECLOG, __func__); + pr_err("%s: %s: ignored ## lpm charging Mode!!\n", SEC_TS_I2C_NAME, __func__); return; } #endif if (p_ghost_check == NULL) { - pr_err("%s: %s %s: ignored ## tsp probe fail!!\n", SEC_TS_I2C_NAME, SECLOG, __func__); + pr_err("%s: %s: ignored ## tsp probe fail!!\n", SEC_TS_I2C_NAME, __func__); return; } schedule_delayed_work(p_ghost_check, msecs_to_jiffies(100)); @@ -551,7 +562,7 @@ static void sec_ts_read_event(struct sec_ts_data *ts) int pre_ttype = 0; if (ts->power_status == SEC_TS_STATE_LPM) { - wake_lock_timeout(&ts->wakelock, msecs_to_jiffies(500)); + //wake_lock_timeout(&ts->wakelock, msecs_to_jiffies(500)); /* waiting for blsp block resuming, if not occurs i2c error */ ret = wait_for_completion_interruptible_timeout(&ts->resume_done, msecs_to_jiffies(500)); @@ -1178,6 +1189,16 @@ static int sec_ts_parse_dt(struct i2c_client *client) input_err(true, dev, "%s: Failed to get tsp-icid gpio\n", __func__); } + pdata->rst_gpio = of_get_named_gpio(np, "sec,rst_gpio", 0); + if (gpio_is_valid(pdata->rst_gpio)) { + ret = gpio_request_one(pdata->rst_gpio, GPIOF_DIR_OUT, "sec,tsp_rst"); + if (ret) { + input_err(true, &client->dev, "%s: Unable to request tsp_rst [%d]\n", __func__, pdata->rst_gpio); + return -EINVAL; + } + } else + input_info(true, &client->dev, "%s: has no rst gpio\n", __func__); + pdata->tsp_vsync = of_get_named_gpio(np, "sec,tsp_vsync_gpio", 0); if (gpio_is_valid(pdata->tsp_vsync)) input_info(true, &client->dev, "%s: vsync %s\n", __func__, @@ -1235,6 +1256,7 @@ static int sec_ts_parse_dt(struct i2c_client *client) if (of_property_read_string_index(np, "sec,project_name", 0, &pdata->project_name)) input_err(true, &client->dev, "%s: skipped to get project_name property\n", __func__); + if (of_property_read_string_index(np, "sec,project_name", 1, &pdata->model_name)) input_err(true, &client->dev, "%s: skipped to get model_name property\n", __func__); @@ -1274,87 +1296,6 @@ static int sec_ts_parse_dt(struct i2c_client *client) return ret; } -int sec_ts_read_information(struct sec_ts_data *ts) -{ - unsigned char data[13] = { 0 }; - int ret; - - memset(data, 0x0, 3); - ret = sec_ts_i2c_read(ts, SEC_TS_READ_ID, data, 3); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read device id(%d)\n", - __func__, ret); - return ret; - } - - input_info(true, &ts->client->dev, - "%s: %X, %X, %X\n", - __func__, data[0], data[1], data[2]); - memset(data, 0x0, 11); - ret = sec_ts_i2c_read(ts, SEC_TS_READ_PANEL_INFO, data, 11); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read sub id(%d)\n", - __func__, ret); - return ret; - } - - input_info(true, &ts->client->dev, - "%s: nTX:%X, nRX:%X, rY:%d, rX:%d\n", - __func__, data[8], data[9], - (data[2] << 8) | data[3], (data[0] << 8) | data[1]); - - /* Set X,Y Resolution from IC information. */ - if (((data[0] << 8) | data[1]) > 0) - ts->plat_data->max_x = ((data[0] << 8) | data[1]) - 1; - - if (((data[2] << 8) | data[3]) > 0) - ts->plat_data->max_y = ((data[2] << 8) | data[3]) - 1; - - ts->tx_count = data[8]; - ts->rx_count = data[9]; - - data[0] = 0; - ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read sub id(%d)\n", - __func__, ret); - return ret; - } - - input_info(true, &ts->client->dev, - "%s: STATUS : %X\n", - __func__, data[0]); - - memset(data, 0x0, 4); - ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, data, 4); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read sub id(%d)\n", - __func__, ret); - return ret; - } - - input_info(true, &ts->client->dev, - "%s: TOUCH STATUS : %02X, %02X, %02X, %02X\n", - __func__, data[0], data[1], data[2], data[3]); - ret = sec_ts_i2c_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, (u8 *)&(ts->touch_functions), 2); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read touch functions(%d)\n", - __func__, ret); - return ret; - } - - input_info(true, &ts->client->dev, - "%s: Functions : %02X\n", - __func__, ts->touch_functions); - - return ret; -} - #ifdef SEC_TS_SUPPORT_CUSTOMLIB int sec_ts_set_custom_library(struct sec_ts_data *ts) { @@ -1459,16 +1400,184 @@ static void sec_ts_set_input_prop(struct sec_ts_data *ts, struct input_dev *dev, input_set_drvdata(dev, ts); } +void sec_ts_sense_on(struct sec_ts_data *ts) +{ + int ret; + + ts->touch_functions |= SEC_TS_DEFAULT_ENABLE_BIT_SETFUNC; + ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, + (u8 *)&ts->touch_functions, 2); + if (ret < 0) + input_err(true, &ts->client->dev, + "%s: Failed to send touch func_mode command", __func__); + /* Sense_on */ + ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0); + if (ret < 0) + input_err(true, &ts->client->dev, + "%s: fail to write Sense_on\n", __func__); +} + +static int sec_ts_read_fw_info(struct sec_ts_data *ts) +{ + unsigned char data[13] = { 0 }; + int ret; + + memset(data, 0x0, 3); + ret = sec_ts_i2c_read(ts, SEC_TS_READ_ID, data, 3); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read device id(%d)\n", + __func__, ret); + return ret; + } + + input_info(true, &ts->client->dev, + "%s: %X, %X, %X\n", + __func__, data[0], data[1], data[2]); + memset(data, 0x0, 11); + ret = sec_ts_i2c_read(ts, SEC_TS_READ_PANEL_INFO, data, 11); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read sub id(%d)\n", + __func__, ret); + return ret; + } + + input_info(true, &ts->client->dev, + "%s: nTX:%X, nRX:%X, rY:%d, rX:%d\n", + __func__, data[8], data[9], + (data[2] << 8) | data[3], (data[0] << 8) | data[1]); + + /* Set X,Y Resolution from IC information. */ + if (((data[0] << 8) | data[1]) > 0) + ts->plat_data->max_x = ((data[0] << 8) | data[1]) - 1; + + if (((data[2] << 8) | data[3]) > 0) + ts->plat_data->max_y = ((data[2] << 8) | data[3]) - 1; + + ts->tx_count = data[8]; + ts->rx_count = data[9]; + + if (ts->pFrame) + kfree(ts->pFrame); + + ts->pFrame = kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL); + if (!ts->pFrame) { + input_err(true, &ts->client->dev, + "%s: failed to alloc frame\n", __func__); + return -ENOMEM; + } + + data[0] = 0; + ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, data, 1); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read sub id(%d)\n", + __func__, ret); + return ret; + } + + input_info(true, &ts->client->dev, + "%s: STATUS : %X\n", + __func__, data[0]); + + memset(data, 0x0, 4); + ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, data, 4); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read sub id(%d)\n", + __func__, ret); + return ret; + } + + input_info(true, &ts->client->dev, + "%s: TOUCH STATUS : %02X, %02X, %02X, %02X\n", + __func__, data[0], data[1], data[2], data[3]); + ret = sec_ts_i2c_read(ts, SEC_TS_CMD_SET_TOUCHFUNCTION, (u8 *)&(ts->touch_functions), 2); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read touch functions(%d)\n", + __func__, ret); + return ret; + } + + input_info(true, &ts->client->dev, + "%s: Functions : %02X\n", + __func__, ts->touch_functions); + + return ret; +} + +static void sec_ts_read_hw_info(struct sec_ts_data *ts) +{ + unsigned char result; + unsigned char buffer[5] = { 0 }; + bool valid_firmware_integrity = false; + int ret; + + ret = sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, buffer, 5); + if (ret < 0) + input_err(true, &ts->client->dev, + "%s: failed to read device ID(%d)\n", __func__, ret); + else { + memcpy(ts->device_id, buffer, sizeof(ts->device_id)); + input_info(true, &ts->client->dev, + "%s: TOUCH DEVICE ID : %02X, %02X, %02X, %02X, %02X\n", __func__, + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); + } + + ret = sec_ts_i2c_read(ts, SEC_TS_READ_FIRMWARE_INTEGRITY, &result, 1); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to integrity check (%d)\n", __func__, ret); + } else { + if (result & 0x80) { + valid_firmware_integrity = true; + } else if (result & 0x40) { + valid_firmware_integrity = false; + input_err(true, &ts->client->dev, + "%s: invalid firmware (0x%x)\n", __func__, result); + } else { + valid_firmware_integrity = false; + input_err(true, &ts->client->dev, + "%s: invalid integrity result (0x%x)\n", __func__, result); + } + } + + memset(buffer, 0, sizeof(buffer)); + ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, &buffer[0], 1); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read sub id(%d)\n", + __func__, ret); + } else { + ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, &buffer[1], 4); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to touch status(%d)\n", + __func__, ret); + } + } + input_info(true, &ts->client->dev, + "%s: TOUCH STATUS : %02X || %02X, %02X, %02X, %02X\n", + __func__, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); + + if (buffer[0] == SEC_TS_STATUS_BOOT_MODE) { + ts->checksum_result = 1; + ts->fw_invalid = true; + } + + if ((buffer[0] == SEC_TS_STATUS_APP_MODE && + buffer[2] == TOUCH_SYSTEM_MODE_FLASH) || + (valid_firmware_integrity == false)) + ts->fw_invalid = true; +} + static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sec_ts_data *ts; struct sec_ts_plat_data *pdata; int ret = 0; - bool force_update = false; - bool valid_firmware_integrity = false; - unsigned char data[5] = { 0 }; - unsigned char deviceID[5] = { 0 }; - unsigned char result = 0; input_info(true, &client->dev, "%s\n", __func__); @@ -1502,20 +1611,13 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i } } - if (!pdata->power) { - input_err(true, &client->dev, "%s: No power contorl found\n", __func__); - goto error_allocate_mem; - } - - pdata->pinctrl = devm_pinctrl_get(&client->dev); - if (IS_ERR(pdata->pinctrl)) - input_err(true, &client->dev, "%s: could not get pinctrl\n", __func__); - + /* init TS static elements */ ts = kzalloc(sizeof(struct sec_ts_data), GFP_KERNEL); if (!ts) goto error_allocate_mem; ts->client = client; + ts->dev = &client->dev; ts->plat_data = pdata; ts->crc_addr = 0x0001FE00; ts->fw_addr = 0x00002000; @@ -1526,6 +1628,16 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i ts->sec_ts_i2c_write_burst = sec_ts_i2c_write_burst; ts->sec_ts_i2c_read_bulk = sec_ts_i2c_read_bulk; ts->i2c_burstmax = pdata->i2c_burstmax; + + if (!pdata->power) { + input_err(true, &client->dev, "%s: No power contorl found\n", __func__); + goto error_allocate_mem; + } + + pdata->pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR(pdata->pinctrl)) + input_err(true, &client->dev, "%s: could not get pinctrl\n", __func__); + #ifdef USE_POWER_RESET_WORK INIT_DELAYED_WORK(&ts->reset_work, sec_ts_reset_work); #endif @@ -1556,8 +1668,6 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i } ts->touch_count = 0; - ts->sec_ts_i2c_write = sec_ts_i2c_write; - ts->sec_ts_i2c_read = sec_ts_i2c_read; ts->sec_ts_read_customlib = sec_ts_read_from_customlib; ts->max_z_value = 0; @@ -1570,7 +1680,7 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i mutex_init(&ts->eventlock); mutex_init(&ts->modechange); - wake_lock_init(&ts->wakelock, WAKE_LOCK_SUSPEND, "tsp_wakelock"); + wakeup_source_init(&ts->wakelock, "tsp_wakelock"); init_completion(&ts->resume_done); complete_all(&ts->resume_done); @@ -1594,55 +1704,8 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i input_info(true, &client->dev, "%s: power enable\n", __func__); - ret = sec_ts_i2c_read(ts, SEC_TS_READ_DEVICE_ID, deviceID, 5); - if (ret < 0) - input_err(true, &ts->client->dev, "%s: failed to read device ID(%d)\n", __func__, ret); - else - input_info(true, &ts->client->dev, - "%s: TOUCH DEVICE ID : %02X, %02X, %02X, %02X, %02X\n", __func__, - deviceID[0], deviceID[1], deviceID[2], deviceID[3], deviceID[4]); - - ret = sec_ts_i2c_read(ts, SEC_TS_READ_FIRMWARE_INTEGRITY, &result, 1); - if (ret < 0) { - input_err(true, &ts->client->dev, "%s: failed to integrity check (%d)\n", __func__, ret); - } else { - if (result & 0x80) { - valid_firmware_integrity = true; - } else if (result & 0x40) { - valid_firmware_integrity = false; - input_err(true, &ts->client->dev, "%s: invalid firmware (0x%x)\n", __func__, result); - } else { - valid_firmware_integrity = false; - input_err(true, &ts->client->dev, "%s: invalid integrity result (0x%x)\n", __func__, result); - } - } - - ret = sec_ts_i2c_read(ts, SEC_TS_READ_BOOT_STATUS, &data[0], 1); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to read sub id(%d)\n", - __func__, ret); - } else { - ret = sec_ts_i2c_read(ts, SEC_TS_READ_TS_STATUS, &data[1], 4); - if (ret < 0) { - input_err(true, &ts->client->dev, - "%s: failed to touch status(%d)\n", - __func__, ret); - } - } - input_info(true, &ts->client->dev, - "%s: TOUCH STATUS : %02X || %02X, %02X, %02X, %02X\n", - __func__, data[0], data[1], data[2], data[3], data[4]); - - if (data[0] == SEC_TS_STATUS_BOOT_MODE) - ts->checksum_result = 1; - - if ((data[0] == SEC_TS_STATUS_APP_MODE && data[2] == TOUCH_SYSTEM_MODE_FLASH) || - (valid_firmware_integrity == false)) - force_update = true; - else - force_update = false; - + sec_ts_read_hw_info(ts); +#if 0 #ifdef SEC_TS_FW_UPDATE_ON_PROBE ret = sec_ts_firmware_update_on_probe(ts, force_update); if (ret < 0) @@ -1650,8 +1713,8 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i #else input_info(true, &ts->client->dev, "%s: fw update on probe disabled!\n", __func__); #endif - - ret = sec_ts_read_information(ts); +#endif + ret = sec_ts_read_fw_info(ts); if (ret < 0) { input_err(true, &ts->client->dev, "%s: fail to read information 0x%x\n", __func__, ret); goto err_init; @@ -1662,19 +1725,6 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i if (ret < 0) input_err(true, &ts->client->dev, "%s: Failed to send touch func_mode command", __func__); - /* Sense_on */ - ret = sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0); - if (ret < 0) { - input_err(true, &ts->client->dev, "%s: fail to write Sense_on\n", __func__); - goto err_init; - } - - ts->pFrame = kzalloc(ts->tx_count * ts->rx_count * 2, GFP_KERNEL); - if (!ts->pFrame) { - ret = -ENOMEM; - goto err_allocate_frame; - } - if (ts->plat_data->support_dex) { ts->input_dev_pad->name = "sec_touchpad"; sec_ts_set_input_prop(ts, ts->input_dev_pad, INPUT_PROP_POINTER); @@ -1711,13 +1761,15 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i goto err_irq; } + /* prevent unbalanced irq enable */ + ts->irq_enabled = true; + /* need remove below resource @ remove driver */ -#if (1) //!defined(CONFIG_SAMSUNG_PRODUCT_SHIP) +#if 0 //!defined(CONFIG_SAMSUNG_PRODUCT_SHIP) sec_ts_raw_device_init(ts); #endif sec_ts_fn_init(ts); - #ifdef SEC_TS_SUPPORT_CUSTOMLIB sec_ts_check_custom_library(ts); if (ts->use_customlib) @@ -1725,6 +1777,10 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i #endif + ret = sec_mmi_data_init(ts, true); + if (ret) + goto err_mmi_data; + device_init_wakeup(&client->dev, true); schedule_delayed_work(&ts->work_read_info, msecs_to_jiffies(50)); @@ -1743,11 +1799,9 @@ static int sec_ts_probe(struct i2c_client *client, const struct i2c_device_id *i return 0; - /* need to be enabled when new goto statement is added */ -#if 0 +err_mmi_data: sec_ts_fn_remove(ts); free_irq(client->irq, ts); -#endif err_irq: if (ts->plat_data->support_dex) { input_unregister_device(ts->input_dev_pad); @@ -1759,9 +1813,8 @@ err_input_pad_register_device: ts->input_dev_touch = NULL; err_input_register_device: kfree(ts->pFrame); -err_allocate_frame: err_init: - wake_lock_destroy(&ts->wakelock); + wakeup_source_trash(&ts->wakelock); sec_ts_power(ts, false); if (ts->plat_data->support_dex) { if (ts->input_dev_pad) @@ -1912,7 +1965,7 @@ static void sec_ts_reset_work(struct work_struct *work) } mutex_lock(&ts->modechange); - wake_lock(&ts->wakelock); + __pm_stay_awake(&ts->wakelock); ts->reset_is_on_going = true; input_info(true, &ts->client->dev, "%s\n", __func__); @@ -1929,12 +1982,12 @@ static void sec_ts_reset_work(struct work_struct *work) schedule_delayed_work(&ts->reset_work, msecs_to_jiffies(TOUCH_RESET_DWORK_TIME)); mutex_unlock(&ts->modechange); - wake_unlock(&ts->wakelock); + __pm_relax(&ts->wakelock); return; } - - if (ts->input_dev_touch->disabled) { + // FIXME: + // if (ts->input_dev_touch->disabled) { input_err(true, &ts->client->dev , "%s: call input_close\n", __func__); if (ts->lowpower_mode) { @@ -1945,7 +1998,7 @@ static void sec_ts_reset_work(struct work_struct *work) cancel_delayed_work(&ts->reset_work); schedule_delayed_work(&ts->reset_work, msecs_to_jiffies(TOUCH_RESET_DWORK_TIME)); mutex_unlock(&ts->modechange); - wake_unlock(&ts->wakelock); + __pm_relax(&ts->wakelock); return; } } else { @@ -1961,7 +2014,7 @@ static void sec_ts_reset_work(struct work_struct *work) data[i * 2 + 3] = (ts->rect_data[i] >> 8) & 0xFF; } - disable_irq(ts->client->irq); + sec_ts_irq_enable(ts, false); ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CUSTOMLIB_WRITE_PARAM, &data[0], 10); if (ret < 0) input_err(true, &ts->client->dev, "%s: Failed to write offset\n", __func__); @@ -1969,13 +2022,14 @@ static void sec_ts_reset_work(struct work_struct *work) ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CUSTOMLIB_NOTIFY_PACKET, NULL, 0); if (ret < 0) input_err(true, &ts->client->dev, "%s: Failed to send notify\n", __func__); - enable_irq(ts->client->irq); + sec_ts_irq_enable(ts, true); } - } + // FIXME: + // } ts->reset_is_on_going = false; mutex_unlock(&ts->modechange); - wake_unlock(&ts->wakelock); + __pm_relax(&ts->wakelock); } #endif @@ -1989,9 +2043,9 @@ static void sec_ts_read_info_work(struct work_struct *work) input_info(true, &ts->client->dev, "%s\n", __func__); /* run self-test */ - disable_irq(ts->client->irq); + sec_ts_irq_enable(ts, false); execute_selftest(ts, false); - enable_irq(ts->client->irq); + sec_ts_irq_enable(ts, true); input_info(true, &ts->client->dev, "%s: %02X %02X %02X %02X\n", __func__, ts->ito_test[0], ts->ito_test[1] @@ -2184,7 +2238,7 @@ static int sec_ts_remove(struct i2c_client *client) p_ghost_check = NULL; #endif device_init_wakeup(&client->dev, false); - wake_lock_destroy(&ts->wakelock); + wakeup_source_trash(&ts->wakelock); ts->lowpower_mode = false; ts->probe_done = false; @@ -2347,14 +2401,14 @@ err: if (ret < 0) input_err(true, &ts->client->dev, "%s: fail to write Sense_on\n", __func__); - enable_irq(ts->client->irq); + sec_ts_irq_enable(ts, true); out: mutex_unlock(&ts->device_mutex); return ret; } -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && !defined(CONFIG_DRM) static int sec_ts_pm_suspend(struct device *dev) { struct sec_ts_data *ts = dev_get_drvdata(dev); @@ -2381,7 +2435,7 @@ static const struct i2c_device_id sec_ts_id[] = { { }, }; -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && !defined(CONFIG_DRM) static const struct dev_pm_ops sec_ts_dev_pm_ops = { .suspend = sec_ts_pm_suspend, .resume = sec_ts_pm_resume, @@ -2408,7 +2462,7 @@ static struct i2c_driver sec_ts_driver = { #ifdef CONFIG_OF .of_match_table = sec_ts_match_table, #endif -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && !defined(CONFIG_DRM) .pm = &sec_ts_dev_pm_ops, #endif }, @@ -2418,12 +2472,11 @@ static int __init sec_ts_init(void) { #ifdef CONFIG_BATTERY_SAMSUNG if (lpcharge == 1) { - pr_err("%s %s: Do not load driver due to : lpm %d\n", - SECLOG, __func__, lpcharge); + pr_err("%s: Do not load driver due to : lpm %d\n", __func__, lpcharge); return -ENODEV; } #endif - pr_err("%s %s\n", SECLOG, __func__); + pr_err("%s\n", __func__); return i2c_add_driver(&sec_ts_driver); } diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts.h b/drivers/input/touchscreen/sec_mmi/sec_ts.h index 84ca197e8829..eb96b39da464 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts.h +++ b/drivers/input/touchscreen/sec_mmi/sec_ts.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -36,24 +35,38 @@ #include #include #include -#include #include +#include "sec_cmd.h" + #ifdef CONFIG_INPUT_BOOSTER #include #endif +#ifndef ABS_MT_CUSTOM +#include "sec_custom.h" +#endif + #ifndef input_info -#define input_info(f, d, fmt, args...) dev_info(d, fmt ##args) +#define input_info(f, d, fmt, args...) dev_info(d, fmt, ##args) #endif #ifndef input_err -#define input_info(f, d, fmt, args...) dev_info(d, fmt ##args) +#define input_err(f, d, fmt, args...) dev_err(d, fmt, ##args) +#endif + +#ifndef input_dbg +#define input_dbg(f, d, fmt, args...) dev_dbg(d, fmt, ##args) +#endif + +#ifndef input_raw_info +#define input_raw_info(f, d, fmt, args...) dev_info(d, fmt, ##args) #endif #define SEC_TS_I2C_NAME "sec_ts" #define SEC_TS_DEVICE_NAME "SEC_TS" +#undef USE_EXTRA_INPUT_FEATURES #define USE_OPEN_CLOSE #undef USE_RESET_DURING_POWER_ON #undef USE_RESET_EXIT_LPM @@ -565,6 +578,7 @@ struct sec_ts_coordinate { u8 left_event; }; +struct sec_mmi_data; struct sec_ts_data { u32 isr_pin; @@ -574,6 +588,7 @@ struct sec_ts_data { u32 para_addr; u32 flash_page_size; u8 boot_ver[3]; + u8 device_id[5]; struct device *dev; struct i2c_client *client; @@ -622,7 +637,7 @@ struct sec_ts_data { volatile bool reset_is_on_going; #endif struct completion resume_done; - struct wake_lock wakelock; + struct wakeup_source wakelock; struct sec_cmd_data sec; short *pFrame; @@ -653,10 +668,8 @@ struct sec_ts_data { int grip_landscape_edge; u16 grip_landscape_deadzone; -#ifdef CONFIG_TOUCHSCREEN_DUMP_MODE struct delayed_work ghost_check; u8 tsp_dump_lock; -#endif int nv; int cal_count; @@ -703,11 +716,16 @@ struct sec_ts_data { int (*sec_ts_i2c_write_burst)(struct sec_ts_data *ts, u8 *data, int len); int (*sec_ts_i2c_read_bulk)(struct sec_ts_data *ts, u8 *data, int len); int (*sec_ts_read_customlib)(struct sec_ts_data *ts, u8 *data, int len); + + struct sec_mmi_data *mmi_ptr; + bool fw_invalid; + bool irq_enabled; }; struct sec_ts_plat_data { int max_x; int max_y; + unsigned rst_gpio; unsigned irq_gpio; int irq_type; int i2c_burstmax; @@ -773,6 +791,7 @@ int sec_ts_power(void *data, bool on); int sec_ts_stop_device(struct sec_ts_data *ts); int sec_ts_start_device(struct sec_ts_data *ts); int sec_ts_set_lowpowermode(struct sec_ts_data *ts, u8 mode); +int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data, size_t size, int bl_update, int restore_cal, int retry); int sec_ts_firmware_update_on_probe(struct sec_ts_data *ts, bool force_update); int sec_ts_firmware_update_on_hidden_menu(struct sec_ts_data *ts, int update_type); int sec_ts_glove_mode_enables(struct sec_ts_data *ts, int mode); @@ -801,6 +820,8 @@ int execute_selftest(struct sec_ts_data *ts, bool save_result); void sec_ts_run_rawdata_all(struct sec_ts_data *ts, bool full_read); void sec_ts_reinit(struct sec_ts_data *ts); +void sec_ts_sense_on(struct sec_ts_data *ts); +void sec_ts_irq_enable(struct sec_ts_data *ts, bool on); #if (1)//!defined(CONFIG_SAMSUNG_PRODUCT_SHIP) @@ -818,5 +839,10 @@ extern unsigned int lpcharge; extern void set_grip_data_to_ic(struct sec_ts_data *ts, u8 flag); extern void sec_ts_set_grip_type(struct sec_ts_data *ts, u8 set_type); - +#ifndef input_log_fix +#define input_log_fix() +#endif +#ifndef input_raw_data_clear +#define input_raw_data_clear() +#endif #endif diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_fn.c b/drivers/input/touchscreen/sec_mmi/sec_ts_fn.c index 99889fa06842..0a07c9830c28 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_fn.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_fn.c @@ -1480,11 +1480,11 @@ static void module_on_master(void *device_data) int ret = 0; ret = sec_ts_start_device(ts); - - if (ts->input_dev->disabled) { + // FIXME + // if (ts->input_dev->disabled) { sec_ts_set_lowpowermode(ts, TO_LOWPOWER_MODE); ts->power_status = SEC_TS_STATE_LPM; - } + // } if (ret == 0) snprintf(buff, sizeof(buff), "%s", "OK"); @@ -1550,7 +1550,7 @@ static void set_mis_cal_spec(void *device_data) sec_cmd_set_default_result(sec); if (ts->plat_data->mis_cal_check == 0) { - input_err(true, &ts->client->dev, "%s: [ERROR] not support, %d\n", __func__); + input_err(true, &ts->client->dev, "%s: [ERROR] not support\n", __func__); goto NG; } else if (ts->power_status == SEC_TS_STATE_POWER_OFF) { input_err(true, &ts->client->dev, "%s: [ERROR] Touch is stopped\n", __func__); @@ -1620,7 +1620,7 @@ static void get_mis_cal_info(void *device_data) sec_cmd_set_default_result(sec); if (ts->plat_data->mis_cal_check == 0) { - input_err(true, &ts->client->dev, "%s: [ERROR] not support, %d\n", __func__); + input_err(true, &ts->client->dev, "%s: [ERROR] not support\n", __func__); mis_cal_data = 0xF1; goto NG; } else if (ts->power_status == SEC_TS_STATE_POWER_OFF) { @@ -2461,7 +2461,7 @@ int get_tsp_nvm_data_by_size(struct sec_ts_data *ts, u8 offset, int length, u8 * if (!buff) return -ENOMEM; - input_info(true, &ts->client->dev, "%s: offset:%u, length:%d, size:%d\n", __func__, offset, length, sizeof(data)); + input_info(true, &ts->client->dev, "%s: offset:%u, length:%d, size:%zu\n", __func__, offset, length, sizeof(data)); /* SENSE OFF -> CELAR EVENT STACK -> READ NV -> SENSE ON */ ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_OFF, NULL, 0); @@ -3819,7 +3819,7 @@ void sec_ts_fn_remove(struct sec_ts_data *ts) { input_err(true, &ts->client->dev, "%s\n", __func__); - sysfs_delete_link(&ts->sec.fac_dev->kobj, &ts->input_dev->dev.kobj, "input"); + sysfs_remove_link(&ts->sec.fac_dev->kobj, "input"); sysfs_remove_group(&ts->sec.fac_dev->kobj, &cmd_attr_group); diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_fw.c b/drivers/input/touchscreen/sec_mmi/sec_ts_fw.c index 708bbe915e1c..856cf48eda39 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_fw.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_fw.c @@ -571,7 +571,7 @@ err_write_fail: return ret; } -static int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data, +int sec_ts_firmware_update(struct sec_ts_data *ts, const u8 *data, size_t size, int bl_update, int restore_cal, int retry) { int i; diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c index 2afaf45c00ec..adf0703c3b7b 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c @@ -10,6 +10,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + +#define DEBUG 511 + #include #include #include @@ -29,14 +32,12 @@ #include #include +#include "sec_ts.h" #include "sec_mmi.h" /* MMI specific sysfs entries and API */ -#define DEV_MMI (&data->i2c_client->dev) -#define DEV_TS (&ts->client->dev) - -static inline ssize_t sec_mmi_store_error(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count); +static ssize_t sec_mmi_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size); static ssize_t sec_mmi_forcereflash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); static ssize_t sec_mmi_doreflash_store(struct device *dev, @@ -45,7 +46,7 @@ static ssize_t sec_mmi_drv_irq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); static ssize_t sec_mmi_drv_irq_show(struct device *dev, struct device_attribute *attr, char *buf); -static inline ssize_t sec_mmi_show_error(struct device *dev, +static ssize_t sec_mmi_hw_irqstat_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t sec_mmi_ic_ver_show(struct device *dev, struct device_attribute *attr, char *buf); @@ -58,14 +59,16 @@ static DEVICE_ATTR(drv_irq, (S_IWUSR | S_IWGRP | S_IRUGO), sec_mmi_drv_irq_show, static DEVICE_ATTR(hw_irqstat, S_IRUGO, sec_mmi_hw_irqstat_show, NULL); static DEVICE_ATTR(ic_ver, S_IRUGO, sec_mmi_ic_ver_show, NULL); static DEVICE_ATTR(poweron, S_IRUGO, sec_mmi_poweron_show, NULL); +static DEVICE_ATTR(reset, (S_IWUSR | S_IWGRP), NULL, sec_mmi_reset_store); static struct attribute *mmi_attributes[] = { - &dev_attr_sec_mmi_forcereflash.attr, - &dev_attr_sec_mmi_fdoreflash.attr, - &dev_attr_sec_mmi_drv_irq.attr, - &dev_attr_sec_mmi_hw_irqstat.attr, - &dev_attr_sec_mmi_ic_ver.attr, - &dev_attr_sec_mmi_poweron.attr, + &dev_attr_forcereflash.attr, + &dev_attr_doreflash.attr, + &dev_attr_drv_irq.attr, + &dev_attr_hw_irqstat.attr, + &dev_attr_ic_ver.attr, + &dev_attr_poweron.attr, + &dev_attr_reset.attr, NULL, }; @@ -82,7 +85,7 @@ static ssize_t path_show(struct device *dev, const char *path; if (!data) { - dev_err(DEV_MMI "data pointer is NULL\n"); + dev_err(DEV_MMI, "data pointer is NULL\n"); return (ssize_t)0; } path = kobject_get_path(&data->i2c_client->dev.kobj, GFP_KERNEL); @@ -107,7 +110,8 @@ static struct device_attribute class_attributes[] = { static int sec_mmi_touchscreen_class( struct sec_mmi_data *data, bool create) { - struct device_attribute *attrs = touchscreen_attributes; + struct device_attribute *attrs = class_attributes; + bool unreg_class = false; int i, error = 0; const char *class_fname = "primary"; static struct class *touchscreen_class; @@ -119,8 +123,10 @@ static int sec_mmi_touchscreen_class( if (minor < 0) minor = input_get_new_minor(TSDEV_MINOR_BASE, TSDEV_MINOR_MAX, true); - dev_info(DEV_MMI, "assigned minor %d\n", minor); + dev_dbg(DEV_MMI, "assigned minor %d\n", minor); + touchscreen_class = get_touchscreen_class_ptr(); + dev_dbg(DEV_MMI, "class ptr %p\n", touchscreen_class); if (!touchscreen_class) { touchscreen_class = class_create(THIS_MODULE, "touchscreen"); if (IS_ERR(touchscreen_class)) { @@ -128,11 +134,14 @@ static int sec_mmi_touchscreen_class( touchscreen_class = NULL; return error; } + set_touchscreen_class_ptr(touchscreen_class); + unreg_class = true; } if (data->class_entry_name) class_fname = data->class_entry_name; + dev_dbg(DEV_MMI, "class entry name %s\n", class_fname); data->ts_class_dev = device_create(touchscreen_class, NULL, MKDEV(INPUT_MAJOR, minor), data, class_fname); if (IS_ERR(data->ts_class_dev)) { @@ -143,8 +152,8 @@ static int sec_mmi_touchscreen_class( dev_set_drvdata(data->ts_class_dev, data); - for (i = 0; class_attrs[i].attr.name != NULL; ++i) { - error = device_create_file(data->ts_class_dev, &class_attrs[i]); + for (i = 0; attrs[i].attr.name != NULL; ++i) { + error = device_create_file(data->ts_class_dev, &attrs[i]); if (error) break; } @@ -155,10 +164,10 @@ static int sec_mmi_touchscreen_class( if (!touchscreen_class || !data->ts_class_dev) return -ENODEV; - dev_set_drvdata(rmi4_data->ts_class_dev, NULL); + dev_set_drvdata(data->ts_class_dev, NULL); - for (i = 0; class_attrs[i].attr.name != NULL; ++i) - device_remove_file(data->ts_class_dev, &class_attrs[i]); + for (i = 0; attrs[i].attr.name != NULL; ++i) + device_remove_file(data->ts_class_dev, &attrs[i]); device_unregister(data->ts_class_dev); data->ts_class_dev = NULL; @@ -168,15 +177,202 @@ static int sec_mmi_touchscreen_class( device_destroy: for (--i; i >= 0; --i) - device_remove_file(data->ts_class_dev, &class_attrs[i]); + device_remove_file(data->ts_class_dev, &attrs[i]); device_destroy(touchscreen_class, MKDEV(INPUT_MAJOR, minor)); data->ts_class_dev = NULL; - class_unregister(touchscreen_class); + if (unreg_class) + class_unregister(touchscreen_class); + touchscreen_class = NULL; dev_err(DEV_MMI, "%s: error creating touchscreen class attrs\n", __func__); return -ENODEV; } +static int sec_mmi_dt(struct sec_mmi_data *data) +{ + struct device *dev = &data->i2c_client->dev; + struct device_node *np = dev->of_node; + + if (!of_property_read_string(np, "sec,class-entry-name", &data->class_entry_name)) + input_info(true, dev, "%s: class-entry-name property %s\n", + __func__, data->class_entry_name); + + if (!of_property_read_string(np, "sec,bound-display", &data->bound_display)) + input_info(true, dev, "%s: bound-display property %s\n", + __func__, data->bound_display); + + if (!of_property_read_u32(np, "sec,control-dsi", &data->ctrl_dsi)) + input_info(true, dev, "%s: ctrl-dsi property %d\n", + __func__, data->ctrl_dsi); + + return 0; +} + +static inline void batohui(unsigned int *dest, unsigned char *src, size_t size) +{ + int si = size; + *dest = 0; + for (; --si >= 0;) + *dest += src[si] << (si << 3); +} + +static void sec_mmi_fw_read_id(struct sec_mmi_data *data) +{ + struct sec_ts_data *ts = data->ts_ptr; + unsigned char buffer[8]; + int ret; + + ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_FW_VERSION, buffer, sizeof(buffer)); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read fw version (%d)\n", + __func__, ret); + } else { + batohui(&data->build_id, buffer, sizeof(data->build_id)); + dev_dbg(DEV_MMI, "%s: FW VERSION: " \ + "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", + __func__, buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], buffer[6], buffer[7]); + } + + memset(buffer, 0, sizeof(buffer)); + ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_PARA_VERSION, buffer, sizeof(buffer)); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read fw version (%d)\n", + __func__, ret); + } else { + batohui(&data->config_id, buffer, sizeof(data->config_id)); + dev_dbg(DEV_MMI, "%s: CONFIG VER: " \ + "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", + __func__, buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], buffer[6], buffer[7]); + } + + memset(buffer, 0, sizeof(buffer)); + ret = ts->sec_ts_i2c_read(ts, SEC_TS_READ_IMG_VERSION, buffer, sizeof(buffer)); + if (ret < 0) { + input_err(true, &ts->client->dev, + "%s: failed to read fw version (%d)\n", + __func__, ret); + } else { + batohui(&data->config_id, buffer, sizeof(data->config_id)); + dev_dbg(DEV_MMI, "%s: IMAGE VER: " \ + "%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", + __func__, buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5], buffer[6], buffer[7]); + } +} + +static void sec_mmi_ic_reset(struct sec_mmi_data *data) +{ + struct sec_ts_data *ts = data->ts_ptr; + + if (!gpio_is_valid(ts->plat_data->rst_gpio) || + !gpio_get_value(ts->plat_data->rst_gpio)) + return; + + mutex_lock(&ts->modechange); + __pm_stay_awake(&ts->wakelock); + + gpio_set_value(ts->plat_data->rst_gpio, 0); + usleep_range(10, 10); + gpio_set_value(ts->plat_data->rst_gpio, 1); + + sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE); + + mutex_unlock(&ts->modechange); + __pm_relax(&ts->wakelock); + + dev_dbg(DEV_MMI, "%s: hw reset done\n", __func__); +} + +static void sec_mmi_wait4idle(struct sec_mmi_data *data) +{ + struct sec_ts_data *ts = data->ts_ptr; + unsigned long start_wait_jiffies = jiffies; + + do { + if (!ts->wakelock.active) + break; + usleep_range(1000, 1000); + } while (1); + + if ((jiffies - start_wait_jiffies)) + dev_info(DEV_MMI, "%s: entering suspend delayed for %ums\n", + __func__, jiffies_to_msecs(jiffies - start_wait_jiffies)); +} + +static void sec_mmi_work(struct work_struct *w) +{ + struct delayed_work *dw = + container_of(w, struct delayed_work, work); + struct sec_mmi_data *data = + container_of(dw, struct sec_mmi_data, detection_work); + struct sec_ts_data *ts = data->ts_ptr; + int probe_status; + bool panel_ready = true; + char *pname = NULL; + +#if defined(CONFIG_DRM) + /* DRM panel status */ + panel_ready = dsi_display_is_panel_enable(data->ctrl_dsi, + &probe_status, &pname); + dev_dbg(DEV_MMI, "%s: drm: probe=%d, enable=%d, panel'%s'\n", + __func__, probe_status, panel_ready, pname); + /* check if bound panel is not present */ + if (pname && strstr(pname, "dummy")) { + dev_info(DEV_MMI, "%s: dummy panel detected\n", __func__); + //rmi4_data->drm_state = DRM_ST_TERM; + } else if (panel_ready) { + dev_dbg(DEV_MMI, "%s: panel ready\n", __func__); + //rmi4_data->drm_state = DRM_ST_READY; + } +#endif + + if (!ts->fw_invalid) { + sec_ts_sense_on(ts); + dev_dbg(DEV_MMI, "%s: sensing turned on\n", __func__); + + sec_mmi_fw_read_id(data); + } +} + +static void sec_mmi_queued_resume(struct work_struct *w) +{ + struct delayed_work *dw = + container_of(w, struct delayed_work, work); + struct sec_mmi_data *data = + container_of(dw, struct sec_mmi_data, resume_work); + struct sec_ts_data *ts = data->ts_ptr; + + if (ts->lowpower_mode) + complete_all(&ts->resume_done); + + dev_dbg(DEV_MMI, "%s: touch resumed\n", __func__); +} + +static int inline sec_mmi_display_on(struct sec_mmi_data *data) +{ + /* schedule_delayed_work returns true if work has been scheduled */ + /* and false otherwise, thus return 0 on success to comply POSIX */ + return schedule_delayed_work(&data->resume_work, 0) == false; +} + +static int inline sec_mmi_display_off(struct sec_mmi_data *data) +{ + struct sec_ts_data *ts = data->ts_ptr; + + cancel_delayed_work_sync(&data->resume_work); + sec_mmi_wait4idle(data); + if (ts->lowpower_mode) + reinit_completion(&ts->resume_done); + + dev_dbg(DEV_MMI, "%s: touch suspended\n", __func__); + + return 0; +} + static int sec_mmi_panel_cb(struct notifier_block *nb, unsigned long event, void *evd) { @@ -202,9 +398,9 @@ static int sec_mmi_panel_cb(struct notifier_block *nb, if (event == MSM_DRM_EARLY_EVENT_BLANK) { if (*blank != MSM_DRM_BLANK_POWERDOWN) return 0; - synaptics_dsx_display_off(&data->i2c_client->dev); + sec_mmi_display_off(data); } else if (*blank == MSM_DRM_BLANK_UNBLANK) { - synaptics_dsx_display_on(&data->i2c_client->dev); + sec_mmi_display_on(data); } } @@ -240,14 +436,70 @@ static ssize_t sec_mmi_poweron_show(struct device *dev, ts->power_status != SEC_TS_STATE_POWER_OFF); } +static ssize_t sec_mmi_hw_irqstat_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%d\n", + ts->power_status != SEC_TS_STATE_POWER_OFF); +} + +static ssize_t sec_mmi_drv_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%s\n", + ts->irq_enabled ? "ENABLED" : "DISABLED"); +} + +static ssize_t sec_mmi_drv_irq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + unsigned long value = 0; + int err = 0; + err = kstrtoul(buf, 10, &value); + if (err < 0) { + dev_err(DEV_TS, "%s: Failed to convert value\n", __func__); + return -EINVAL; + } + switch (value) { + case 0: /* Disable irq */ + sec_ts_irq_enable(ts, false); + break; + case 1: /* Enable irq */ + sec_ts_irq_enable(ts, true); + break; + default: + dev_err(DEV_TS, "%s: invalid value\n", __func__); + return -EINVAL; + } + return size; +} + +static ssize_t sec_mmi_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct sec_ts_data *ts = dev_get_drvdata(dev); + sec_mmi_ic_reset(ts->mmi_ptr); + return 0; +} + static ssize_t sec_mmi_ic_ver_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sec_ts_data *ts = dev_get_drvdata(dev); + struct sec_mmi_data *data = ts->mmi_ptr; return scnprintf(buf, PAGE_SIZE, "%s%s\n%s%x\n%s%x\n", - "Product ID: ", rmi->product_id_string, - "Build ID: ", build_id, - "Config ID: ", config_id); + "Product ID: ", data->product_id, + "Build ID: ", data->build_id, + "Config ID: ", data->config_id); +} + +static ssize_t sec_mmi_forcereflash_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + return 0; } static ssize_t sec_mmi_doreflash_store(struct device *dev, @@ -259,9 +511,7 @@ static ssize_t sec_mmi_doreflash_store(struct device *dev, int result = -1; if (size > SEC_TS_MAX_FW_PATH) { - dev_err(&rmi4_data->i2c_client->dev, - "%s: FW filename is too long\n", - __func__); + dev_err(DEV_TS, "%s: FW filename is too long\n", __func__); return -EINVAL; } @@ -285,135 +535,90 @@ err_request_fw: return result; } -static ssize_t sec_ts_regreadsize_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static void sec_mmi_sysfs(struct sec_mmi_data *data, bool enable) { - struct sec_ts_data *ts = dev_get_drvdata(dev); + struct sec_ts_data *ts = data->ts_ptr; - mutex_lock(&ts->device_mutex); + if (enable) { + int ret; - lv1cmd = buf[0]; - lv1_readsize = ((unsigned int)buf[4] << 24) | - ((unsigned int)buf[3] << 16) | ((unsigned int) buf[2] << 8) | ((unsigned int)buf[1] << 0); - lv1_readoffset = 0; - lv1_readremain = 0; - - mutex_unlock(&ts->device_mutex); - - return size; + ret = sysfs_create_group(&ts->dev->kobj, &mmi_attr_group); + if (ret < 0) { + input_err(true, DEV_TS, + "%s: Failed to create MMI sysfs attributes\n", __func__); + } + } else + sysfs_remove_group(&ts->dev->kobj, &mmi_attr_group); } -static ssize_t sec_ts_enter_recovery_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +int sec_mmi_data_init(struct sec_ts_data *ts, bool enable) { - struct sec_ts_data *ts = dev_get_drvdata(dev); - struct sec_ts_plat_data *pdata = ts->plat_data; - int ret; - unsigned long on; + struct sec_mmi_data *data; - ret = kstrtoul(buf, 10, &on); - if (ret != 0) { - input_err(true, &ts->client->dev, "%s: failed to read:%d\n", - __func__, ret); - return -EINVAL; + if (enable) + data = kzalloc(sizeof(*data), GFP_KERNEL); + else + data = ts->mmi_ptr; + + if (!data) { + input_err(true, DEV_TS, "%s: MMI data is NULL\n", __func__); + return 0; } - if (on == 1) { - disable_irq(ts->client->irq); - gpio_free(pdata->irq_gpio); + if (enable) { +#if defined(CONFIG_DRM) + int probe_status; + bool panel_ready = true; + char *pname = NULL; +#endif - input_info(true, &ts->client->dev, "%s: gpio free\n", __func__); - if (gpio_is_valid(pdata->irq_gpio)) { - ret = gpio_request_one(pdata->irq_gpio, GPIOF_OUT_INIT_LOW, "sec,tsp_int"); - input_info(true, &ts->client->dev, "%s: gpio request one\n", __func__); - if (ret < 0) - input_err(true, &ts->client->dev, "%s: Unable to request tsp_int [%d]: %d\n", __func__, pdata->irq_gpio, ret); - } else { - input_err(true, &ts->client->dev, "%s: Failed to get irq gpio\n", __func__); - return -EINVAL; + ts->mmi_ptr = (void *)data; + data->ts_ptr = ts; + data->i2c_client = ts->client; + data->hard_reset = sec_mmi_ic_reset; + + sec_mmi_dt(data); + +#if defined(CONFIG_DRM) + /* DRM panel status */ + panel_ready = dsi_display_is_panel_enable(data->ctrl_dsi, + &probe_status, &pname); + input_info(true, DEV_TS, "%s: drm: probe=%d, enable=%d, panel'%s'\n", + __func__, probe_status, panel_ready, pname); + /* check panel binding */ + if (data->bound_display && (probe_status == -ENODEV || + (pname && strncmp(pname, data->bound_display, + strlen(data->bound_display))))) { + input_err(true, DEV_TS, "%s: panel binding failed\n", __func__); + return -ENODEV; } - pdata->power(ts, false); - sec_ts_delay(100); - pdata->power(ts, true); - } else { - gpio_free(pdata->irq_gpio); - - if (gpio_is_valid(pdata->irq_gpio)) { - ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "sec,tsp_int"); - if (ret) { - input_err(true, &ts->client->dev, "%s: Unable to request tsp_int [%d]\n", __func__, pdata->irq_gpio); - return -EINVAL; - } - } else { - input_err(true, &ts->client->dev, "%s: Failed to get irq gpio\n", __func__); - return -EINVAL; + if (pname && strstr(pname, "dummy")) { + input_info(true, DEV_TS, "%s: dummy panel; exiting...\n", __func__); + return -ENODEV; } +#endif + snprintf(data->product_id, sizeof(data->product_id), "%c%c%c%02x", + tolower(ts->device_id[0]), tolower(ts->device_id[1]), + ts->device_id[2], ts->device_id[3]); - pdata->power(ts, false); - sec_ts_delay(500); - pdata->power(ts, true); - sec_ts_delay(500); + INIT_DELAYED_WORK(&data->resume_work, sec_mmi_queued_resume); + INIT_DELAYED_WORK(&data->detection_work, sec_mmi_work); - /* AFE Calibration */ - ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_CALIBRATION_AMBIENT, NULL, 0); - if (ret < 0) - input_err(true, &ts->client->dev, "%s: fail to write AFE_CAL\n", __func__); - - sec_ts_delay(1000); - enable_irq(ts->client->irq); + schedule_delayed_work(&data->detection_work, msecs_to_jiffies(50)); } - sec_ts_read_information(ts); + sec_mmi_touchscreen_class(data, enable); + sec_mmi_register_notifier(data, enable); + sec_mmi_sysfs(data, enable); - return size; -} - -static inline ssize_t sec_ts_show_error(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sec_ts_data *ts = dev_get_drvdata(dev); - - input_err(true, &ts->client->dev, "%s: read only function, %s\n", __func__, attr->attr.name); - return -EPERM; -} - -static inline ssize_t sec_ts_store_error(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct sec_ts_data *ts = dev_get_drvdata(dev); - - input_err(true, &ts->client->dev, "%s: write only function, %s\n", __func__, attr->attr.name); - return -EPERM; -} - -int sec_ts_raw_device_init(struct sec_ts_data *ts) -{ - int ret; - - struct class *sec_class = NULL; - - sec_class = class_create(THIS_MODULE, "sec"); - ret = IS_ERR_OR_NULL(sec_class); - if (ret) { - input_err(true, &ts->client->dev, "%s: fail - class_create\n", __func__); - return; + if (!enable) { + sec_mmi_sysfs(data, true); + cancel_delayed_work(&data->resume_work); + cancel_delayed_work(&data->detection_work); + kfree(data); + ts->mmi_ptr = NULL; } - ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts"); - - ret = IS_ERR(ts->dev); - if (ret) { - input_err(true, &ts->client->dev, "%s: fail - device_create\n", __func__); - return ret; - } - - ret = sysfs_create_group(&ts->dev->kobj, &cmd_attr_group); - if (ret < 0) { - input_err(true, &ts->client->dev, "%s: fail - sysfs_create_group\n", __func__); - goto err_sysfs; - } - - return ret; -err_sysfs: - input_err(true, &ts->client->dev, "%s: fail\n", __func__); - return ret; + return 0; } diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_only_vendor.c b/drivers/input/touchscreen/sec_mmi/sec_ts_only_vendor.c index 27e98eee2b1e..a1203ee74ff6 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_only_vendor.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_only_vendor.c @@ -271,7 +271,7 @@ int sec_ts_raw_device_init(struct sec_ts_data *ts) ret = IS_ERR_OR_NULL(sec_class); if (ret) { input_err(true, &ts->client->dev, "%s: fail - class_create\n", __func__); - return; + return ret; } ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts");