mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 13:49:24 -04:00
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 <hcv867@motorola.com> Reviewed-on: https://gerrit.mot.com/1387460 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Konstantin Makariev <kmakariev@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
bada97e392
commit
9a8a94046a
11 changed files with 1326 additions and 356 deletions
|
|
@ -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
|
||||
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
|
||||
|
|
|
|||
558
drivers/input/touchscreen/sec_mmi/sec_cmd.c
Normal file
558
drivers/input/touchscreen/sec_mmi/sec_cmd.c
Normal file
|
|
@ -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");
|
||||
|
||||
|
||||
91
drivers/input/touchscreen/sec_mmi/sec_cmd.h
Normal file
91
drivers/input/touchscreen/sec_mmi/sec_cmd.h
Normal file
|
|
@ -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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/input.h>
|
||||
#if 0
|
||||
#ifdef CONFIG_SEC_SYSFS
|
||||
//#include <linux/sec_sysfs.h>
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SEC_FACTORY
|
||||
#include <linux/kfifo.h>
|
||||
#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_ */
|
||||
|
||||
|
||||
14
drivers/input/touchscreen/sec_mmi/sec_custom.h
Normal file
14
drivers/input/touchscreen/sec_mmi/sec_custom.h
Normal file
|
|
@ -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_ */
|
||||
|
||||
|
||||
|
|
@ -4,22 +4,43 @@
|
|||
#include <linux/major.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#if defined(CONFIG_DRM)
|
||||
#include <linux/msm_drm_notify.h>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/sec_cmd.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
@ -36,24 +35,38 @@
|
|||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "sec_cmd.h"
|
||||
|
||||
#ifdef CONFIG_INPUT_BOOSTER
|
||||
#include <linux/input/input_booster.h>
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define DEBUG 511
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -29,14 +32,12 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Reference in a new issue